]> granicus.if.org Git - clang/commitdiff
Change RetainCountChecker to eagerly "escape" retained objects when they are
authorTed Kremenek <kremenek@apple.com>
Tue, 27 Mar 2012 01:12:45 +0000 (01:12 +0000)
committerTed Kremenek <kremenek@apple.com>
Tue, 27 Mar 2012 01:12:45 +0000 (01:12 +0000)
assigned to a struct.  This is fallout from inlining results, which expose
far more patterns where people stuff CF objects into structs and pass them
around (and we can reason about it).  The problem is that we don't have
a general way to detect when values have escaped, so as an intermediate step
we need to eagerly prune out such tracking.

Fixes <rdar://problem/11104566>.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153489 91177308-0d34-0410-b5e6-96231b3b80d8

lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
test/Analysis/retain-release-region-store.m
test/Analysis/retain-release.m

index 92557961728977915717214907ae3d1e313e7de7..a6d33ad2a0f74d3e161ad5fa1e59305f8d2ff6fe 100644 (file)
@@ -3341,6 +3341,12 @@ void RetainCountChecker::checkBind(SVal loc, SVal val, const Stmt *S,
       // the binding).
       escapes = (state == (state->bindLoc(*regionLoc, val)));
     }
+    if (!escapes) {
+      // Case 4: We do not currently model what happens when a symbol is
+      // assigned to a struct field, so be conservative here and let the symbol
+      // go. TODO: This could definitely be improved upon.
+      escapes = !isa<VarRegion>(regionLoc->getRegion());
+    }
   }
 
   // If our store can represent the binding and we aren't storing to something
index 1ff31b710dad92be6645ca023b30b15756576085..917381341a4be809493f83b50a1d78a527a6ef6e 100644 (file)
@@ -100,6 +100,10 @@ struct foo {
   NSDate* f;
 };
 
+// FIXME: We should be warning about a use-after-free here, but we
+// temporarily "escape" retain counted objects stored to structs very eagerly
+// until we can properly tell whether they have escaped via a return value
+// or not.
 CFAbsoluteTime f4() {
   struct foo x;
   
@@ -110,7 +114,8 @@ CFAbsoluteTime f4() {
   CFDateGetAbsoluteTime(date); // no-warning
   x.f = (NSDate*) date;  
   [((NSDate*) date) release];
-  t = CFDateGetAbsoluteTime(date);   // expected-warning{{Reference-counted object is used after it is released}}
+  // FIXME: the following line should warn.
+  t = CFDateGetAbsoluteTime(date);   // no-warning
   return t;
 }
 
index 8b0e7b83a7b9128159b33d414803cd819e5739f9..fb02427eb45feebb53082b3653cc568c4481044e 100644 (file)
@@ -1667,6 +1667,29 @@ void rdar_10824732() {
   }
 }
 
+//===----------------------------------------------------------------------===//
+// Test returning allocated memory in a struct.
+// 
+// We currently don't have a general way to track pointers that "escape".
+// Here we test that RetainCountChecker doesn't get excited about returning
+// allocated CF objects in struct fields.
+//===----------------------------------------------------------------------===//
+void *malloc(size_t);
+struct rdar11104566 { CFStringRef myStr; };
+struct rdar11104566 test_rdar11104566() {
+  CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+  struct rdar11104566 V;
+  V.myStr = cf;
+  return V; // no-warning
+}
+
+struct rdar11104566 *test_2_rdar11104566() {
+  CFStringRef cf = CFStringCreateWithCString( ((CFAllocatorRef)0), "test", kCFStringEncodingUTF8 ); // no-warning
+  struct rdar11104566 *V = (struct rdar11104566 *) malloc(sizeof(*V));
+  V->myStr = cf;
+  return V; // no-warning
+}
+
 //===----------------------------------------------------------------------===//
 // ObjC literals support.
 //===----------------------------------------------------------------------===//