From 9d9d3a67bd690eb8beaa9dab4a56c89967613083 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Fri, 8 May 2009 23:09:42 +0000 Subject: [PATCH] retain/release checker: Refactor error-reporting code in EvalDeadSymbols and EvalEndPath. This sets the stage for handling autorelease counts. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71283 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Analysis/CFRefCount.cpp | 206 +++++++++++++++++------------------- 1 file changed, 98 insertions(+), 108 deletions(-) diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index 2d154759b2..3c3441156a 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -159,6 +159,31 @@ ResolveToInterfaceMethodDecl(const ObjCMethodDecl *MD, ASTContext &Context) { : ID->lookupClassMethod(Context, MD->getSelector()); } +namespace { +class VISIBILITY_HIDDEN GenericNodeBuilder { + GRStmtNodeBuilder *SNB; + Stmt *S; + const void *tag; + GREndPathNodeBuilder *ENB; +public: + GenericNodeBuilder(GRStmtNodeBuilder &snb, Stmt *s, + const void *t) + : SNB(&snb), S(s), tag(t), ENB(0) {} + GenericNodeBuilder(GREndPathNodeBuilder &enb) + : SNB(0), S(0), tag(0), ENB(&enb) {} + + ExplodedNode *MakeNode(const GRState *state, + ExplodedNode *Pred) { + if (SNB) + return SNB->generateNode(PostStmt(S, tag), state, + Pred); + + assert(ENB); + return ENB->MakeNode(state, Pred); + } +}; +} // end anonymous namespace + //===----------------------------------------------------------------------===// // Selector creation functions. //===----------------------------------------------------------------------===// @@ -1539,7 +1564,6 @@ void RefVal::print(std::ostream& Out) const { typedef llvm::ImmutableMap RefBindings; static int RefBIndex = 0; -static std::pair LeakProgramPointTag(&RefBIndex, 0); namespace clang { template<> @@ -1634,9 +1658,14 @@ private: const GRState* St, RefVal::Kind hasErr, SymbolRef Sym); - std::pair - HandleSymbolDeath(GRStateManager& VMgr, const GRState* St, - const Decl* CD, SymbolRef sid, RefVal V, bool& hasLeak); + GRStateRef HandleSymbolDeath(GRStateRef state, SymbolRef sid, RefVal V, + llvm::SmallVectorImpl &Leaked); + + ExplodedNode* ProcessLeaks(GRStateRef state, + llvm::SmallVectorImpl &Leaked, + GenericNodeBuilder &Builder, + GRExprEngine &Eng, + ExplodedNode *Pred = 0); public: CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts) @@ -2854,30 +2883,6 @@ void CFRefCount::EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) { B.MakeNode(state.scanReachableSymbols(val).getState()); } -std::pair -CFRefCount::HandleSymbolDeath(GRStateManager& VMgr, - const GRState* St, const Decl* CD, - SymbolRef sid, - RefVal V, bool& hasLeak) { - - // Any remaining leaks? - hasLeak = V.isOwned() || - ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0); - - GRStateRef state(St, VMgr); - - if (!hasLeak) - return std::make_pair(state.remove(sid), false); - - return std::make_pair(state.set(sid, V ^ RefVal::ErrorLeak), - false); -} - - - -// Dead symbols. - - // Return statements. @@ -2932,7 +2937,7 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, // Did we cache out? if (!Pred) return; - + // Any leaks or other errors? if (X.isReturnedOwned() && X.getCount() == 0) { const Decl *CD = &Eng.getStateManager().getCodeDecl(); @@ -2953,6 +2958,8 @@ void CFRefCount::EvalReturn(ExplodedNodeSet& Dst, } } } + + } // Assumptions. @@ -3125,43 +3132,60 @@ GRStateRef CFRefCount::Update(GRStateRef state, SymbolRef sym, // Handle dead symbols and end-of-path. //===----------------------------------------------------------------------===// -void CFRefCount::EvalEndPath(GRExprEngine& Eng, - GREndPathNodeBuilder& Builder) { + +GRStateRef +CFRefCount::HandleSymbolDeath(GRStateRef state, SymbolRef sid, RefVal V, + llvm::SmallVectorImpl &Leaked) { - const GRState* St = Builder.getState(); - RefBindings B = St->get(); + bool hasLeak = V.isOwned() || + ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0); - llvm::SmallVector, 10> Leaked; - const Decl* CodeDecl = &Eng.getGraph().getCodeDecl(); + if (!hasLeak) + return state.remove(sid); - for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { - bool hasLeak = false; - - std::pair X = - HandleSymbolDeath(Eng.getStateManager(), St, CodeDecl, - (*I).first, (*I).second, hasLeak); - - St = X.first; - if (hasLeak) Leaked.push_back(std::make_pair((*I).first, X.second)); - } + Leaked.push_back(sid); + return state.set(sid, V ^ RefVal::ErrorLeak); +} + +ExplodedNode* +CFRefCount::ProcessLeaks(GRStateRef state, + llvm::SmallVectorImpl &Leaked, + GenericNodeBuilder &Builder, + GRExprEngine& Eng, + ExplodedNode *Pred) { if (Leaked.empty()) - return; - - ExplodedNode* N = Builder.MakeNode(St); + return Pred; - if (!N) - return; + ExplodedNode *N = Builder.MakeNode(state, Pred); - for (llvm::SmallVector, 10>::iterator - I = Leaked.begin(), E = Leaked.end(); I != E; ++I) { - - CFRefBug *BT = static_cast(I->second ? leakAtReturn - : leakWithinFunction); - assert(BT && "BugType not initialized."); - CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, I->first, Eng); - BR->EmitReport(report); + if (N) { + for (llvm::SmallVectorImpl::iterator + I = Leaked.begin(), E = Leaked.end(); I != E; ++I) { + + CFRefBug *BT = static_cast(Pred ? leakWithinFunction + : leakAtReturn); + assert(BT && "BugType not initialized."); + CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, *I, Eng); + BR->EmitReport(report); + } } + + return N; +} + +void CFRefCount::EvalEndPath(GRExprEngine& Eng, + GREndPathNodeBuilder& Builder) { + + GRStateRef state(Builder.getState(), Eng.getStateManager()); + RefBindings B = state.get(); + llvm::SmallVector Leaked; + + for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) + state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked); + + GenericNodeBuilder Bd(Builder); + ProcessLeaks(state, Leaked, Bd, Eng, NULL); } void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, @@ -3171,65 +3195,31 @@ void CFRefCount::EvalDeadSymbols(ExplodedNodeSet& Dst, Stmt* S, const GRState* St, SymbolReaper& SymReaper) { - - // FIXME: a lot of copy-and-paste from EvalEndPath. Refactor. + + GRStateRef state(St, Eng.getStateManager()); RefBindings B = St->get(); - llvm::SmallVector, 10> Leaked; + llvm::SmallVector Leaked; for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), - E = SymReaper.dead_end(); I != E; ++I) { - - const RefVal* T = B.lookup(*I); - if (!T) continue; - - bool hasLeak = false; - - std::pair X - = HandleSymbolDeath(Eng.getStateManager(), St, 0, *I, *T, hasLeak); - - St = X.first; - - if (hasLeak) - Leaked.push_back(std::make_pair(*I,X.second)); - } + E = SymReaper.dead_end(); I != E; ++I) { + if (const RefVal* T = B.lookup(*I)) + state = HandleSymbolDeath(state, *I, *T, Leaked); + } - 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* N = - Builder.generateNode(PostStmtCustom(S, &LeakProgramPointTag), St, Pred); + static unsigned LeakPPTag = 0; + GenericNodeBuilder Bd(Builder, S, &LeakPPTag); + Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred); - if (!N) - return; - - // Generate the bug reports. - for (llvm::SmallVectorImpl >::iterator - I = Leaked.begin(), E = Leaked.end(); I != E; ++I) { - - CFRefBug *BT = static_cast(I->second ? leakAtReturn - : leakWithinFunction); - assert(BT && "BugType not initialized."); - CFRefLeakReport* report = new CFRefLeakReport(*BT, *this, N, - I->first, Eng); - BR->EmitReport(report); - } - - Pred = N; - } + // Did we cache out? + if (!Pred) + return; // Now generate a new node that nukes the old bindings. - GRStateRef state(St, Eng.getStateManager()); RefBindings::Factory& F = state.get_context(); - + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), - E = SymReaper.dead_end(); I!=E; ++I) - B = F.Remove(B, *I); - + E = SymReaper.dead_end(); I!=E; ++I) B = F.Remove(B, *I); + state = state.set(B); Builder.MakeNode(Dst, S, Pred, state); } -- 2.40.0