diff options
author | Ted Kremenek <kremenek@apple.com> | 2009-02-19 23:47:02 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2009-02-19 23:47:02 +0000 |
commit | 33b6f6352d3c7e4eb026ce129f48a72061a4e129 (patch) | |
tree | 3f5b52e5d686d2d1ac3044a32191a4264309779e /lib/Analysis/CFRefCount.cpp | |
parent | d0344a4a6182ad704881cbbaa21cca14913d2296 (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.cpp | 55 |
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, |