diff options
author | Ted Kremenek <kremenek@apple.com> | 2009-12-03 08:25:47 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2009-12-03 08:25:47 +0000 |
commit | 2ffbfd96a3f1c2e55c0e950d941fbb4dbcd137b9 (patch) | |
tree | 7a21e964e5c9d57dc9c65a3aa340d4291dfb32f7 | |
parent | 81cef5889027d0f96b24afa7a0bb28d9023474ed (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.cpp | 12 | ||||
-rw-r--r-- | lib/Analysis/RegionStore.cpp | 13 | ||||
-rw-r--r-- | test/Analysis/misc-ps-region-store.m | 27 |
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; +} + |