diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/CheckerManager.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/CheckerManager.cpp | 174 |
1 files changed, 119 insertions, 55 deletions
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index acacfb0..0bcc343 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -93,6 +93,9 @@ template <typename CHECK_CTX> static void expandGraphWithCheckers(CHECK_CTX checkCtx, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src) { + const NodeBuilderContext &BldrCtx = checkCtx.Eng.getBuilderContext(); + if (Src.empty()) + return; typename CHECK_CTX::CheckersTy::const_iterator I = checkCtx.checkers_begin(), E = checkCtx.checkers_end(); @@ -113,9 +116,15 @@ static void expandGraphWithCheckers(CHECK_CTX checkCtx, CurrSet->clear(); } + NodeBuilder B(*PrevSet, *CurrSet, BldrCtx); for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checkCtx.runChecker(*I, *CurrSet, *NI); + NI != NE; ++NI) { + checkCtx.runChecker(*I, B, *NI); + } + + // If all the produced transitions are sinks, stop. + if (CurrSet->empty()) + return; // Update which NodeSet is the current one. PrevSet = CurrSet; @@ -129,23 +138,24 @@ namespace { const CheckersTy &Checkers; const Stmt *S; ExprEngine &Eng; + bool wasInlined; CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } CheckersTy::const_iterator checkers_end() { return Checkers.end(); } CheckStmtContext(bool isPreVisit, const CheckersTy &checkers, - const Stmt *s, ExprEngine &eng) - : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { } + const Stmt *s, ExprEngine &eng, bool wasInlined = false) + : IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng), + wasInlined(wasInlined) {} void runChecker(CheckerManager::CheckStmtFunc checkFn, - ExplodedNodeSet &Dst, ExplodedNode *Pred) { + NodeBuilder &Bldr, ExplodedNode *Pred) { // FIXME: Remove respondsToCallback from CheckerContext; ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : ProgramPoint::PostStmtKind; const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, Pred->getLocationContext(), checkFn.Checker); - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); - + CheckerContext C(Bldr, Eng, Pred, L, wasInlined); checkFn(S, C); } }; @@ -156,9 +166,10 @@ void CheckerManager::runCheckersForStmt(bool isPreVisit, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, - ExprEngine &Eng) { + ExprEngine &Eng, + bool wasInlined) { CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit), - S, Eng); + S, Eng, wasInlined); expandGraphWithCheckers(C, Dst, Src); } @@ -178,12 +189,14 @@ namespace { : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { } void runChecker(CheckerManager::CheckObjCMessageFunc checkFn, - ExplodedNodeSet &Dst, ExplodedNode *Pred) { + NodeBuilder &Bldr, ExplodedNode *Pred) { ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind : ProgramPoint::PostStmtKind; - const ProgramPoint &L = ProgramPoint::getProgramPoint(Msg.getOriginExpr(), - K, Pred->getLocationContext(), checkFn.Checker); - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + const ProgramPoint &L = + ProgramPoint::getProgramPoint(Msg.getMessageExpr(), + K, Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); checkFn(Msg, C); } @@ -209,35 +222,44 @@ namespace { const CheckersTy &Checkers; SVal Loc; bool IsLoad; - const Stmt *S; + const Stmt *NodeEx; /* Will become a CFGStmt */ + const Stmt *BoundEx; ExprEngine &Eng; CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } CheckersTy::const_iterator checkers_end() { return Checkers.end(); } CheckLocationContext(const CheckersTy &checkers, - SVal loc, bool isLoad, const Stmt *s, ExprEngine &eng) - : Checkers(checkers), Loc(loc), IsLoad(isLoad), S(s), Eng(eng) { } + SVal loc, bool isLoad, const Stmt *NodeEx, + const Stmt *BoundEx, + ExprEngine &eng) + : Checkers(checkers), Loc(loc), IsLoad(isLoad), NodeEx(NodeEx), + BoundEx(BoundEx), Eng(eng) {} void runChecker(CheckerManager::CheckLocationFunc checkFn, - ExplodedNodeSet &Dst, ExplodedNode *Pred) { + NodeBuilder &Bldr, ExplodedNode *Pred) { ProgramPoint::Kind K = IsLoad ? ProgramPoint::PreLoadKind : ProgramPoint::PreStoreKind; - const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, - Pred->getLocationContext(), checkFn.Checker); - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); - - checkFn(Loc, IsLoad, S, C); + const ProgramPoint &L = + ProgramPoint::getProgramPoint(NodeEx, K, + Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + checkFn(Loc, IsLoad, BoundEx, C); } }; } /// \brief Run checkers for load/store of a location. + void CheckerManager::runCheckersForLocation(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SVal location, bool isLoad, - const Stmt *S, ExprEngine &Eng) { - CheckLocationContext C(LocationCheckers, location, isLoad, S, Eng); + const Stmt *NodeEx, + const Stmt *BoundEx, + ExprEngine &Eng) { + CheckLocationContext C(LocationCheckers, location, isLoad, NodeEx, + BoundEx, Eng); expandGraphWithCheckers(C, Dst, Src); } @@ -249,20 +271,21 @@ namespace { SVal Val; const Stmt *S; ExprEngine &Eng; + ProgramPoint::Kind PointKind; CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } CheckersTy::const_iterator checkers_end() { return Checkers.end(); } CheckBindContext(const CheckersTy &checkers, - SVal loc, SVal val, const Stmt *s, ExprEngine &eng) - : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng) { } + SVal loc, SVal val, const Stmt *s, ExprEngine &eng, + ProgramPoint::Kind PK) + : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {} void runChecker(CheckerManager::CheckBindFunc checkFn, - ExplodedNodeSet &Dst, ExplodedNode *Pred) { - ProgramPoint::Kind K = ProgramPoint::PreStmtKind; - const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, + NodeBuilder &Bldr, ExplodedNode *Pred) { + const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind, Pred->getLocationContext(), checkFn.Checker); - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + CheckerContext C(Bldr, Eng, Pred, L); checkFn(Loc, Val, S, C); } @@ -273,8 +296,9 @@ namespace { void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SVal location, SVal val, - const Stmt *S, ExprEngine &Eng) { - CheckBindContext C(BindCheckers, location, val, S, Eng); + const Stmt *S, ExprEngine &Eng, + ProgramPoint::Kind PointKind) { + CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind); expandGraphWithCheckers(C, Dst, Src); } @@ -286,27 +310,65 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, } /// \brief Run checkers for end of path. -void CheckerManager::runCheckersForEndPath(EndOfFunctionNodeBuilder &B, +// Note, We do not chain the checker output (like in expandGraphWithCheckers) +// for this callback since end of path nodes are expected to be final. +void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC, + ExplodedNodeSet &Dst, ExprEngine &Eng) { + ExplodedNode *Pred = BC.Pred; + + // We define the builder outside of the loop bacause if at least one checkers + // creates a sucsessor for Pred, we do not need to generate an + // autotransition for it. + NodeBuilder Bldr(Pred, Dst, BC); for (unsigned i = 0, e = EndPathCheckers.size(); i != e; ++i) { - CheckEndPathFunc fn = EndPathCheckers[i]; - EndOfFunctionNodeBuilder specialB = B.withCheckerTag(fn.Checker); - fn(specialB, Eng); + CheckEndPathFunc checkFn = EndPathCheckers[i]; + + const ProgramPoint &L = BlockEntrance(BC.Block, + Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + checkFn(C); } } +namespace { + struct CheckBranchConditionContext { + typedef std::vector<CheckerManager::CheckBranchConditionFunc> CheckersTy; + const CheckersTy &Checkers; + const Stmt *Condition; + ExprEngine &Eng; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckBranchConditionContext(const CheckersTy &checkers, + const Stmt *Cond, ExprEngine &eng) + : Checkers(checkers), Condition(Cond), Eng(eng) {} + + void runChecker(CheckerManager::CheckBranchConditionFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + ProgramPoint L = PostCondition(Condition, Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + checkFn(Condition, C); + } + }; +} + /// \brief Run checkers for branch condition. -void CheckerManager::runCheckersForBranchCondition(const Stmt *condition, - BranchNodeBuilder &B, +void CheckerManager::runCheckersForBranchCondition(const Stmt *Condition, + ExplodedNodeSet &Dst, + ExplodedNode *Pred, ExprEngine &Eng) { - for (unsigned i = 0, e = BranchConditionCheckers.size(); i != e; ++i) { - CheckBranchConditionFunc fn = BranchConditionCheckers[i]; - fn(condition, B, Eng); - } + ExplodedNodeSet Src; + Src.insert(Pred); + CheckBranchConditionContext C(BranchConditionCheckers, Condition, Eng); + expandGraphWithCheckers(C, Dst, Src); } /// \brief Run checkers for live symbols. -void CheckerManager::runCheckersForLiveSymbols(const ProgramState *state, +void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, SymbolReaper &SymReaper) { for (unsigned i = 0, e = LiveSymbolsCheckers.size(); i != e; ++i) LiveSymbolsCheckers[i](state, SymReaper); @@ -328,11 +390,11 @@ namespace { : Checkers(checkers), SR(sr), S(s), Eng(eng) { } void runChecker(CheckerManager::CheckDeadSymbolsFunc checkFn, - ExplodedNodeSet &Dst, ExplodedNode *Pred) { + NodeBuilder &Bldr, ExplodedNode *Pred) { ProgramPoint::Kind K = ProgramPoint::PostPurgeDeadSymbolsKind; const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K, Pred->getLocationContext(), checkFn.Checker); - CheckerContext C(Dst, Eng.getBuilder(), Eng, Pred, L, 0); + CheckerContext C(Bldr, Eng, Pred, L); checkFn(SR, C); } @@ -350,7 +412,7 @@ void CheckerManager::runCheckersForDeadSymbols(ExplodedNodeSet &Dst, } /// \brief True if at least one checker wants to check region changes. -bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) { +bool CheckerManager::wantsRegionChangeUpdate(ProgramStateRef state) { for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) if (RegionChangesCheckers[i].WantUpdateFn(state)) return true; @@ -359,25 +421,26 @@ bool CheckerManager::wantsRegionChangeUpdate(const ProgramState *state) { } /// \brief Run checkers for region changes. -const ProgramState * -CheckerManager::runCheckersForRegionChanges(const ProgramState *state, +ProgramStateRef +CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, const StoreManager::InvalidatedSymbols *invalidated, ArrayRef<const MemRegion *> ExplicitRegions, - ArrayRef<const MemRegion *> Regions) { + ArrayRef<const MemRegion *> Regions, + const CallOrObjCMessage *Call) { for (unsigned i = 0, e = RegionChangesCheckers.size(); i != e; ++i) { // If any checker declares the state infeasible (or if it starts that way), // bail out. if (!state) return NULL; state = RegionChangesCheckers[i].CheckFn(state, invalidated, - ExplicitRegions, Regions); + ExplicitRegions, Regions, Call); } return state; } /// \brief Run checkers for handling assumptions on symbolic values. -const ProgramState * -CheckerManager::runCheckersForEvalAssume(const ProgramState *state, +ProgramStateRef +CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, SVal Cond, bool Assumption) { for (unsigned i = 0, e = EvalAssumeCheckers.size(); i != e; ++i) { // If any checker declares the state infeasible (or if it starts that way), @@ -437,11 +500,12 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, } #endif + ExplodedNodeSet checkDst; + NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); // Next, check if any of the EvalCall callbacks can evaluate the call. for (std::vector<EvalCallFunc>::iterator EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); EI != EE; ++EI) { - ExplodedNodeSet checkDst; ProgramPoint::Kind K = ProgramPoint::PostStmtKind; const ProgramPoint &L = ProgramPoint::getProgramPoint(CE, K, Pred->getLocationContext(), EI->Checker); @@ -449,7 +513,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, { // CheckerContext generates transitions(populates checkDest) on // destruction, so introduce the scope to make sure it gets properly // populated. - CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, L, 0); + CheckerContext C(B, Eng, Pred, L); evaluated = (*EI)(CE, C); } assert(!(evaluated && anyEvaluated) @@ -483,7 +547,7 @@ void CheckerManager::runCheckersOnEndOfTranslationUnit( } void CheckerManager::runCheckersForPrintState(raw_ostream &Out, - const ProgramState *State, + ProgramStateRef State, const char *NL, const char *Sep) { for (llvm::DenseMap<CheckerTag, CheckerRef>::iterator I = CheckerTags.begin(), E = CheckerTags.end(); I != E; ++I) |