]> granicus.if.org Git - clang/commitdiff
Add value invalidation logic for block-captured variables. Conceptually invoking...
authorTed Kremenek <kremenek@apple.com>
Thu, 3 Dec 2009 08:25:47 +0000 (08:25 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 3 Dec 2009 08:25:47 +0000 (08:25 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90431 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/CFRefCount.cpp
lib/Analysis/RegionStore.cpp
test/Analysis/misc-ps-region-store.m

index 0b69a4c5ae3a2c1abe08f46b9a53b83bb93af7df..288645d2272d1572cc0d6b34c29738ce3fedd173 100644 (file)
@@ -1984,6 +1984,7 @@ public:
                    Expr* Ex,
                    Expr* Receiver,
                    const RetainSummary& Summ,
+                   const MemRegion *Callee,
                    ExprIterator arg_beg, ExprIterator arg_end,
                    ExplodedNode* Pred, const GRState *state);
 
@@ -2777,6 +2778,7 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
                              Expr* Ex,
                              Expr* Receiver,
                              const RetainSummary& Summ,
+                             const MemRegion *Callee,
                              ExprIterator arg_beg, ExprIterator arg_end,
                              ExplodedNode* Pred, const GRState *state) {
 
@@ -2856,6 +2858,12 @@ void CFRefCount::EvalSummary(ExplodedNodeSet& Dst,
     }
   }
   
+  // Block calls result in all captured values passed-via-reference to be
+  // invalidated.
+  if (const BlockDataRegion *BR = dyn_cast_or_null<BlockDataRegion>(Callee)) {
+    RegionsToInvalidate.push_back(BR);
+  }
+  
   // Invalidate regions we designed for invalidation use the batch invalidation
   // API.
   if (!RegionsToInvalidate.empty()) {    
@@ -3025,7 +3033,7 @@ void CFRefCount::EvalCall(ExplodedNodeSet& Dst,
   }
 
   assert(Summ);
-  EvalSummary(Dst, Eng, Builder, CE, 0, *Summ,
+  EvalSummary(Dst, Eng, Builder, CE, 0, *Summ, L.getAsRegion(),
               CE->arg_begin(), CE->arg_end(), Pred, Builder.GetState(Pred));
 }
 
@@ -3041,7 +3049,7 @@ void CFRefCount::EvalObjCMessageExpr(ExplodedNodeSet& Dst,
       : Summaries.getClassMethodSummary(ME);
 
   assert(Summ && "RetainSummary is null");
-  EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ,
+  EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL,
               ME->arg_begin(), ME->arg_end(), Pred, state);
 }
 
index 170abc8fe6f1ffd202d190d0b9586fb302730344..6c452c23dccac911fc9ce3b10923e9679aa9ef5e 100644 (file)
@@ -522,6 +522,19 @@ const GRState *RegionStoreManager::InvalidateRegions(const GRState *state,
       if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
         IS->insert(SR->getSymbol());
     }
+    
+    // BlockDataRegion?  If so, invalidate captured variables that are passed
+    // by reference.
+    if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
+      for (BlockDataRegion::referenced_vars_iterator
+            I = BR->referenced_vars_begin(), E = BR->referenced_vars_end() ;
+           I != E; ++I) {
+        const VarRegion *VR = *I;
+        if (VR->getDecl()->getAttr<BlocksAttr>())
+          WorkList.push_back(VR);
+      }
+      continue;
+    }
 
     // Handle the region itself.
     if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) ||
index e5113ba351c8fdcb3dec3244fd2d5aec44bfa00a..9d6825a75e2c969dd0b5c755bdb9fb9ba5dd188b 100644 (file)
@@ -541,3 +541,30 @@ double rdar_6811085(void) {
   return u + 10; // expected-warning{{The left operand of '+' is a garbage value}}
 }
 
+//===----------------------------------------------------------------------===//
+// Path-sensitive tests for blocks.
+//===----------------------------------------------------------------------===//
+
+void indirect_block_call(void (^f)());
+
+int blocks_1(int *p, int z) {
+  __block int *q = 0;
+  void (^bar)() = ^{ q = p; };
+  
+  if (z == 1) {
+    // The call to 'bar' might cause 'q' to be invalidated.
+    bar();
+    *q = 0x1; // no-warning
+  }
+  else if (z == 2) {
+    // The function 'indirect_block_call' might invoke bar, thus causing
+    // 'q' to possibly be invalidated.
+    indirect_block_call(bar);
+    *q = 0x1; // no-warning
+  }
+  else {
+    *q = 0xDEADBEEF; // expected-warning{{Dereference of null pointer}}
+  }
+  return z;
+}
+