aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/CFRefCount.cpp
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2009-02-19 23:47:02 +0000
committerTed Kremenek <kremenek@apple.com>2009-02-19 23:47:02 +0000
commit33b6f6352d3c7e4eb026ce129f48a72061a4e129 (patch)
tree3f5b52e5d686d2d1ac3044a32191a4264309779e /lib/Analysis/CFRefCount.cpp
parentd0344a4a6182ad704881cbbaa21cca14913d2296 (diff)
retain/release checker: Generate an intermediate simulation node for "leak"
transitions and then generate a subsequent node that removes the dead symbol bindings. This should drastically improve caching in the simulation graph when retain-counted objects are being tracked. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65082 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis/CFRefCount.cpp')
-rw-r--r--lib/Analysis/CFRefCount.cpp55
1 files changed, 38 insertions, 17 deletions
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index c86b960af1..36c1b79af3 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -1245,6 +1245,7 @@ void RefVal::print(std::ostream& Out) const {
typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings;
static int RefBIndex = 0;
+static std::pair<const void*, const void*> LeakProgramPointTag(&RefBIndex, 0);
namespace clang {
template<>
@@ -2745,8 +2746,7 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
const GRState* St,
SymbolReaper& SymReaper) {
- // FIXME: a lot of copy-and-paste from EvalEndPath. Refactor.
-
+ // FIXME: a lot of copy-and-paste from EvalEndPath. Refactor.
RefBindings B = St->get<RefBindings>();
llvm::SmallVector<std::pair<SymbolRef,bool>, 10> Leaked;
@@ -2759,7 +2759,7 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
bool hasLeak = false;
std::pair<GRStateRef, bool> X
- = HandleSymbolDeath(Eng.getStateManager(), St, 0, *I, *T, hasLeak);
+ = HandleSymbolDeath(Eng.getStateManager(), St, 0, *I, *T, hasLeak);
St = X.first;
@@ -2767,23 +2767,44 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet<GRState>& Dst,
Leaked.push_back(std::make_pair(*I,X.second));
}
- if (Leaked.empty())
- return;
-
- ExplodedNode<GRState>* N = Builder.MakeNode(Dst, S, Pred, St);
-
- if (!N)
- return;
+ if (!Leaked.empty()) {
+ // Create a new intermediate node representing the leak point. We
+ // use a special program point that represents this checker-specific
+ // transition. We use the address of RefBIndex as a unique tag for this
+ // checker. We will create another node (if we don't cache out) that
+ // removes the retain-count bindings from the state.
+ // NOTE: We use 'generateNode' so that it does interplay with the
+ // auto-transition logic.
+ ExplodedNode<GRState>* N =
+ Builder.generateNode(PostStmtCustom(S, &LeakProgramPointTag), St, Pred);
- for (llvm::SmallVector<std::pair<SymbolRef,bool>, 10>::iterator
- I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
+ if (!N)
+ return;
+
+ // Generate the bug reports.
+ for (llvm::SmallVectorImpl<std::pair<SymbolRef,bool> >::iterator
+ I = Leaked.begin(), E = Leaked.end(); I != E; ++I) {
+
+ CFRefBug *BT = static_cast<CFRefBug*>(I->second ? leakAtReturn
+ : leakWithinFunction);
+ assert(BT && "BugType not initialized.");
+ CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, I->first, Eng);
+ BR->EmitReport(report);
+ }
- CFRefBug *BT = static_cast<CFRefBug*>(I->second ? leakAtReturn
- : leakWithinFunction);
- assert(BT && "BugType not initialized.");
- CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, I->first, Eng);
- BR->EmitReport(report);
+ Pred = N;
}
+
+ // Now generate a new node that nukes the old bindings.
+ GRStateRef state(St, Eng.getStateManager());
+ RefBindings::Factory& F = state.get_context<RefBindings>();
+
+ for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
+ E = SymReaper.dead_end(); I!=E; ++I)
+ B = F.Remove(B, *I);
+
+ state = state.set<RefBindings>(B);
+ Builder.MakeNode(Dst, S, Pred, state);
}
void CFRefCount::ProcessNonLeakError(ExplodedNodeSet<GRState>& Dst,