From: Jordy Rose Date: Tue, 23 Aug 2011 19:01:07 +0000 (+0000) Subject: [analyzer] Move symbol death leak analysis from CFRefCount to RetainReleaseChecker. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=38f17d6c86417944403dfa2b0d50a0dc92efa9ce;p=clang [analyzer] Move symbol death leak analysis from CFRefCount to RetainReleaseChecker. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@138353 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp index 4577737598..15f1cc5337 100644 --- a/lib/StaticAnalyzer/Core/CFRefCount.cpp +++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp @@ -1649,8 +1649,6 @@ public: BugType *overAutorelease; BugType *returnNotOwnedForOwned; BugReporter *BR; - - llvm::DenseMap DeadSymbolTags; const ProgramState *Update(const ProgramState * state, SymbolRef sym, @@ -1658,17 +1656,6 @@ public: ArgEffect E, RefVal::Kind& hasErr); - const ProgramState *HandleSymbolDeath(const ProgramState * state, - SymbolRef sid, - RefVal V, - SmallVectorImpl &Leaked); - - ExplodedNode *ProcessLeaks(const ProgramState * state, - SmallVectorImpl &Leaked, - GenericNodeBuilderRefCount &Builder, - ExprEngine &Eng, - ExplodedNode *Pred = 0); - public: CFRefCount(ASTContext &Ctx, bool gcenabled, const LangOptions& lopts) : Summaries(Ctx, gcenabled, (bool)lopts.ObjCAutoRefCount), @@ -1677,12 +1664,6 @@ public: leakWithinFunction(0), leakAtReturn(0), overAutorelease(0), returnNotOwnedForOwned(0), BR(0) {} - virtual ~CFRefCount() { - for (llvm::DenseMap::iterator - it = DeadSymbolTags.begin(), ei = DeadSymbolTags.end(); it != ei; ++it) - delete it->second; - } - void RegisterChecks(ExprEngine &Eng); virtual void RegisterPrinters(std::vector& Printers) { @@ -1723,18 +1704,6 @@ public: // End-of-path. - virtual void evalEndPath(ExprEngine& Engine, - EndOfFunctionNodeBuilder& Builder); - - virtual void evalDeadSymbols(ExplodedNodeSet &Dst, - ExprEngine& Engine, - StmtNodeBuilder& Builder, - ExplodedNode *Pred, - const ProgramState *state, - SymbolReaper& SymReaper); - - const ProgramPointTag *getDeadSymbolTag(SymbolRef sym); - std::pair HandleAutoreleaseCounts(const ProgramState * state, GenericNodeBuilderRefCount Bd, @@ -3062,142 +3031,6 @@ CFRefCount::HandleAutoreleaseCounts(const ProgramState *state, return std::make_pair((ExplodedNode*)0, state); } -const ProgramState * -CFRefCount::HandleSymbolDeath(const ProgramState *state, - SymbolRef sid, - RefVal V, - SmallVectorImpl &Leaked) { - - bool hasLeak = V.isOwned() || - ((V.isNotOwned() || V.isReturnedOwned()) && V.getCount() > 0); - - if (!hasLeak) - return state->remove(sid); - - Leaked.push_back(sid); - return state->set(sid, V ^ RefVal::ErrorLeak); -} - -ExplodedNode* -CFRefCount::ProcessLeaks(const ProgramState * state, - SmallVectorImpl &Leaked, - GenericNodeBuilderRefCount &Builder, - ExprEngine& Eng, - ExplodedNode *Pred) { - - if (Leaked.empty()) - return Pred; - - // Generate an intermediate node representing the leak point. - ExplodedNode *N = Builder.MakeNode(state, Pred); - - if (N) { - for (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(ExprEngine& Eng, - EndOfFunctionNodeBuilder& Builder) { - - const ProgramState *state = Builder.getState(); - GenericNodeBuilderRefCount Bd(Builder); - RefBindings B = state->get(); - ExplodedNode *Pred = 0; - - for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { - bool stop = false; - llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng, - (*I).first, - (*I).second, stop); - - if (stop) - return; - } - - B = state->get(); - SmallVector Leaked; - - for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) - state = HandleSymbolDeath(state, (*I).first, (*I).second, Leaked); - - ProcessLeaks(state, Leaked, Bd, Eng, Pred); -} - -const ProgramPointTag *CFRefCount::getDeadSymbolTag(SymbolRef sym) { - const SimpleProgramPointTag *&tag = DeadSymbolTags[sym]; - if (!tag) { - llvm::SmallString<128> buf; - llvm::raw_svector_ostream out(buf); - out << "CFRefCount : Dead Symbol : " << sym->getSymbolID(); - tag = new SimpleProgramPointTag(out.str()); - } - return tag; -} - -void CFRefCount::evalDeadSymbols(ExplodedNodeSet &Dst, - ExprEngine& Eng, - StmtNodeBuilder& Builder, - ExplodedNode *Pred, - const ProgramState *state, - SymbolReaper& SymReaper) { - const Stmt *S = Builder.getStmt(); - RefBindings B = state->get(); - - // Update counts from autorelease pools - for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), - E = SymReaper.dead_end(); I != E; ++I) { - SymbolRef Sym = *I; - if (const RefVal* T = B.lookup(Sym)){ - // Use the symbol as the tag. - // FIXME: This might not be as unique as we would like. - GenericNodeBuilderRefCount Bd(Builder, S, getDeadSymbolTag(Sym)); - bool stop = false; - llvm::tie(Pred, state) = HandleAutoreleaseCounts(state, Bd, Pred, Eng, - Sym, *T, stop); - if (stop) - return; - } - } - - B = state->get(); - SmallVector Leaked; - - for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), - E = SymReaper.dead_end(); I != E; ++I) { - if (const RefVal* T = B.lookup(*I)) - state = HandleSymbolDeath(state, *I, *T, Leaked); - } - - static SimpleProgramPointTag LeakPPTag("CFRefCount : Leak"); - { - GenericNodeBuilderRefCount Bd(Builder, S, &LeakPPTag); - Pred = ProcessLeaks(state, Leaked, Bd, Eng, Pred); - } - - // Did we cache out? - if (!Pred) - return; - - // Now generate a new node that nukes the old bindings. - 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); - - state = state->set(B); - Builder.MakeNode(Dst, S, Pred, state); -} - //===----------------------------------------------------------------------===// // Pieces of the retain/release checker implemented using a CheckerVisitor. // More pieces of the retain/release checker will be migrated to this interface @@ -3207,6 +3040,8 @@ void CFRefCount::evalDeadSymbols(ExplodedNodeSet &Dst, namespace { class RetainReleaseChecker : public Checker< check::Bind, + check::DeadSymbols, + check::EndPath, check::PostStmt, check::PostStmt, check::PostStmt, @@ -3214,7 +3049,18 @@ class RetainReleaseChecker check::RegionChanges, eval::Assume, eval::Call > { + + typedef llvm::DenseMap SymbolTagMap; + + // This map is only used to ensure proper deletion of any allocated tags. + mutable SymbolTagMap DeadSymbolTags; + public: + + virtual ~RetainReleaseChecker() { + DeleteContainerSeconds(DeadSymbolTags); + } + void checkBind(SVal loc, SVal val, CheckerContext &C) const; void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; void checkPostStmt(const CastExpr *CE, CheckerContext &C) const; @@ -3238,10 +3084,24 @@ public: return true; } + void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; + void checkEndPath(EndOfFunctionNodeBuilder &Builder, ExprEngine &Eng) const; + void processNonLeakError(const ProgramState *St, SourceRange ErrorRange, RefVal::Kind ErrorKind, SymbolRef Sym, CheckerContext &C) const; + const ProgramPointTag *getDeadSymbolTag(SymbolRef sym) const; + + const ProgramState *handleSymbolDeath(const ProgramState *state, + SymbolRef sid, RefVal V, + SmallVectorImpl &Leaked) const; + + ExplodedNode *processLeaks(const ProgramState *state, + SmallVectorImpl &Leaked, + GenericNodeBuilderRefCount &Builder, + ExprEngine &Eng, + ExplodedNode *Pred = 0) const; }; } // end anonymous namespace @@ -3727,6 +3587,155 @@ bool RetainReleaseChecker::evalCall(const CallExpr *CE, return true; } +// Handle dead symbols (potential leaks). + +const ProgramState * +RetainReleaseChecker::handleSymbolDeath(const ProgramState *state, + SymbolRef sid, RefVal V, + SmallVectorImpl &Leaked) const { + bool hasLeak; + if (V.isOwned()) + hasLeak = true; + else if (V.isNotOwned() || V.isReturnedOwned()) + hasLeak = (V.getCount() > 0); + + if (!hasLeak) + return state->remove(sid); + + Leaked.push_back(sid); + return state->set(sid, V ^ RefVal::ErrorLeak); +} + +ExplodedNode * +RetainReleaseChecker::processLeaks(const ProgramState *state, + SmallVectorImpl &Leaked, + GenericNodeBuilderRefCount &Builder, + ExprEngine &Eng, + ExplodedNode *Pred) const { + + if (Leaked.empty()) + return Pred; + + // Generate an intermediate node representing the leak point. + ExplodedNode *N = Builder.MakeNode(state, Pred); + + if (N) { + for (SmallVectorImpl::iterator + I = Leaked.begin(), E = Leaked.end(); I != E; ++I) { + + // FIXME: This goes away once the these bug types move to the checker, + // and CFRefReport no longer depends on CFRefCount. + CFRefCount &TF = static_cast(Eng.getTF()); + CFRefBug *BT = static_cast(Pred ? TF.leakWithinFunction + : TF.leakAtReturn); + assert(BT && "BugType not initialized."); + CFRefLeakReport *report = new CFRefLeakReport(*BT, TF, N, *I, Eng); + Eng.getBugReporter().EmitReport(report); + } + } + + return N; +} + +void RetainReleaseChecker::checkEndPath(EndOfFunctionNodeBuilder &Builder, + ExprEngine &Eng) const { + // FIXME: This goes away once HandleAutoreleaseCounts moves to the checker. + CFRefCount &TF = static_cast(Eng.getTF()); + + const ProgramState *state = Builder.getState(); + GenericNodeBuilderRefCount Bd(Builder); + RefBindings B = state->get(); + ExplodedNode *Pred = 0; + + for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { + bool stop = false; + llvm::tie(Pred, state) = TF.HandleAutoreleaseCounts(state, Bd, Pred, Eng, + (*I).first, + (*I).second, stop); + + if (stop) + return; + } + + B = state->get(); + SmallVector Leaked; + + for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) + state = handleSymbolDeath(state, (*I).first, (*I).second, Leaked); + + processLeaks(state, Leaked, Bd, Eng, Pred); +} + +const ProgramPointTag * +RetainReleaseChecker::getDeadSymbolTag(SymbolRef sym) const { + const SimpleProgramPointTag *&tag = DeadSymbolTags[sym]; + if (!tag) { + llvm::SmallString<64> buf; + llvm::raw_svector_ostream out(buf); + out << "RetainReleaseChecker : Dead Symbol : " << sym->getSymbolID(); + tag = new SimpleProgramPointTag(out.str()); + } + return tag; +} + +void RetainReleaseChecker::checkDeadSymbols(SymbolReaper &SymReaper, + CheckerContext &C) const { + StmtNodeBuilder &Builder = C.getNodeBuilder(); + ExprEngine &Eng = C.getEngine(); + const Stmt *S = C.getStmt(); + ExplodedNode *Pred = C.getPredecessor(); + + // FIXME: This goes away once HandleAutoreleaseCounts moves to the checker. + CFRefCount &TF = static_cast(Eng.getTF()); + + const ProgramState *state = C.getState(); + RefBindings B = state->get(); + + // Update counts from autorelease pools + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), + E = SymReaper.dead_end(); I != E; ++I) { + SymbolRef Sym = *I; + if (const RefVal *T = B.lookup(Sym)){ + // Use the symbol as the tag. + // FIXME: This might not be as unique as we would like. + GenericNodeBuilderRefCount Bd(Builder, S, getDeadSymbolTag(Sym)); + bool stop = false; + llvm::tie(Pred, state) = TF.HandleAutoreleaseCounts(state, Bd, Pred, Eng, + Sym, *T, stop); + if (stop) + return; + } + } + + B = state->get(); + SmallVector Leaked; + + for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), + E = SymReaper.dead_end(); I != E; ++I) { + if (const RefVal *T = B.lookup(*I)) + state = handleSymbolDeath(state, *I, *T, Leaked); + } + + { + GenericNodeBuilderRefCount Bd(Builder, S, this); + Pred = processLeaks(state, Leaked, Bd, Eng, Pred); + } + + // Did we cache out? + if (!Pred) + return; + + // Now generate a new node that nukes the old bindings. + 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); + + state = state->set(B); + C.generateNode(state, Pred); +} + //===----------------------------------------------------------------------===// // Transfer function creation for external clients. //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 1b72672dca..a555b77296 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -283,6 +283,9 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { ExplodedNodeSet Tmp2; getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode, EntryState, SymReaper); + if (Tmp2.empty()) { + Builder->MakeNode(Tmp2, currentStmt, EntryNode, EntryState); + } ExplodedNodeSet Tmp3; getCheckerManager().runCheckersForDeadSymbols(Tmp3, Tmp2,