aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2009-12-03 08:25:47 +0000
committerTed Kremenek <kremenek@apple.com>2009-12-03 08:25:47 +0000
commit2ffbfd96a3f1c2e55c0e950d941fbb4dbcd137b9 (patch)
tree7a21e964e5c9d57dc9c65a3aa340d4291dfb32f7
parent81cef5889027d0f96b24afa7a0bb28d9023474ed (diff)
Add value invalidation logic for block-captured variables. Conceptually invoking a block (without specific reasoning of what the block does) can invalidate any value to it by reference when the block was created.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90431 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Analysis/CFRefCount.cpp12
-rw-r--r--lib/Analysis/RegionStore.cpp13
-rw-r--r--test/Analysis/misc-ps-region-store.m27
3 files changed, 50 insertions, 2 deletions
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index 0b69a4c5ae..288645d227 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -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);
}
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 170abc8fe6..6c452c23dc 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -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) ||
diff --git a/test/Analysis/misc-ps-region-store.m b/test/Analysis/misc-ps-region-store.m
index e5113ba351..9d6825a75e 100644
--- a/test/Analysis/misc-ps-region-store.m
+++ b/test/Analysis/misc-ps-region-store.m
@@ -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;
+}
+