From: Argyrios Kyrtzidis Date: Tue, 1 Mar 2011 01:16:03 +0000 (+0000) Subject: [analyzer] Remove checker V1 registration and running from ExprEngine. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=eb48bd1dd4168ab206a330bf523659170291a6a0;p=clang [analyzer] Remove checker V1 registration and running from ExprEngine. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@126724 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 16f54ee746..529a5c937b 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -74,39 +74,6 @@ class ExprEngine : public SubEngine { Selector* NSExceptionInstanceRaiseSelectors; Selector RaiseSel; - enum CallbackKind { - PreVisitStmtCallback, - PostVisitStmtCallback, - processAssumeCallback, - EvalRegionChangesCallback - }; - - typedef uint32_t CallbackTag; - - /// GetCallbackTag - Create a tag for a certain kind of callback. The 'Sub' - /// argument can be used to differentiate callbacks that depend on another - /// value from a small set of possibilities, such as statement classes. - static inline CallbackTag GetCallbackTag(CallbackKind K, uint32_t Sub = 0) { - assert(Sub == ((Sub << 8) >> 8) && "Tag sub-kind must fit into 24 bits"); - return K | (Sub << 8); - } - - typedef llvm::DenseMap CheckerMap; - typedef std::vector > CheckersOrdered; - typedef llvm::DenseMap CheckersOrderedCache; - - /// A registration map from checker tag to the index into the - /// ordered checkers vector. - CheckerMap CheckerM; - - /// An ordered vector of checkers that are called when evaluating - /// various expressions and statements. - CheckersOrdered Checkers; - - /// A map used for caching the checkers that respond to the callback for - /// a particular callback tag. - CheckersOrderedCache COCache; - /// The BugReporter associated with this engine. It is important that /// this object be placed at the very end of member variables so that its /// destructor is called before the rest of the ExprEngine is destroyed. @@ -165,21 +132,6 @@ public: ExplodedGraph& getGraph() { return G; } const ExplodedGraph& getGraph() const { return G; } - template - void registerCheck(CHECKER *check) { - unsigned entry = Checkers.size(); - void *tag = CHECKER::getTag(); - Checkers.push_back(std::make_pair(tag, check)); - CheckerM[tag] = entry; - } - - Checker *lookupChecker(void *tag) const; - - template - CHECKER *getChecker() const { - return static_cast(lookupChecker(CHECKER::getTag())); - } - /// processCFGElement - Called by CoreEngine. Used to generate new successor /// nodes by processing the 'effects' of a CFG element. void processCFGElement(const CFGElement E, StmtNodeBuilder& builder); @@ -281,27 +233,6 @@ public: ProgramPoint::Kind K = ProgramPoint::PostStmtKind, const void *tag = 0); - /// CheckerVisit - Dispatcher for performing checker-specific logic - /// at specific statements. - void CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src, - CallbackKind Kind); - - void CheckerVisitObjCMessage(const ObjCMessage &msg, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, bool isPrevisit); - - bool CheckerEvalCall(const CallExpr *CE, - ExplodedNodeSet &Dst, - ExplodedNode *Pred); - - void CheckerEvalNilReceiver(const ObjCMessage &msg, - ExplodedNodeSet &Dst, - const GRState *state, - ExplodedNode *Pred); - - void CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, SVal location, SVal val, - bool isPrevisit); - /// Visit - Transfer function logic for all statements. Dispatches to /// other functions that handle specific kinds of statements. void Visit(const Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst); diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index 6dfbedc3bb..5b142a9810 100644 --- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -59,248 +59,6 @@ static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) { return Ctx.Selectors.getSelector(0, &II); } -//===----------------------------------------------------------------------===// -// Checker worklist routines. -//===----------------------------------------------------------------------===// - -void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, CallbackKind Kind) { - - // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for the provided . This - // can reduce the number of checkers actually called. - CheckersOrdered *CO = &Checkers; - llvm::OwningPtr NewCO; - - // The cache key is made up of the and the callback kind (pre- or post-visit) - // and the statement kind. - CallbackTag K = GetCallbackTag(Kind, S->getStmtClass()); - - CheckersOrdered *& CO_Ref = COCache[K]; - - if (!CO_Ref) { - // If we have no previously cached CheckersOrdered vector for this - // statement kind, then create one. - NewCO.reset(new CheckersOrdered); - } - else { - // Use the already cached set. - CO = CO_Ref; - } - - if (CO->empty()) { - // If there are no checkers, just delegate to the checker manager. - getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback, - Dst, Src, S, *this); - return; - } - - ExplodedNodeSet CheckersV1Dst; - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - unsigned checkersEvaluated = 0; - - for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I) { - // If all nodes are sunk, bail out early. - if (PrevSet->empty()) - break; - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &CheckersV1Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - void *tag = I->first; - Checker *checker = I->second; - bool respondsToCallback = true; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) { - - checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag, - Kind == PreVisitStmtCallback, respondsToCallback); - - } - - PrevSet = CurrSet; - - if (NewCO.get()) { - ++checkersEvaluated; - if (respondsToCallback) - NewCO->push_back(*I); - } - } - - // If we built NewCO, check if we called all the checkers. This is important - // so that we know that we accurately determined the entire set of checkers - // that responds to this callback. Note that 'checkersEvaluated' might - // not be the same as Checkers.size() if one of the Checkers generates - // a sink node. - if (NewCO.get() && checkersEvaluated == Checkers.size()) - CO_Ref = NewCO.take(); - - // Don't autotransition. The CheckerContext objects should do this - // automatically. - - getCheckerManager().runCheckersForStmt(Kind == PreVisitStmtCallback, - Dst, CheckersV1Dst, S, *this); -} - -void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg, - ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, - bool isPrevisit) { - - if (Checkers.empty()) { - getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, Src, msg, - *this); - return; - } - - ExplodedNodeSet CheckersV1Dst; - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &CheckersV1Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_visitObjCMessage(*CurrSet, *Builder, *this, msg, - *NI, tag, isPrevisit); - - // Update which NodeSet is the current one. - PrevSet = CurrSet; - } - - getCheckerManager().runCheckersForObjCMessage(isPrevisit, Dst, CheckersV1Dst, - msg, *this); -} - -void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg, - ExplodedNodeSet &Dst, - const GRState *state, - ExplodedNode *Pred) { - bool evaluated = false; - ExplodedNodeSet DstTmp; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { - void *tag = I->first; - Checker *checker = I->second; - - if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, msg, Pred, state, - tag)) { - evaluated = true; - break; - } else - // The checker didn't evaluate the expr. Restore the Dst. - DstTmp.clear(); - } - - if (evaluated) - Dst.insert(DstTmp); - else - Dst.insert(Pred); -} - -// CheckerEvalCall returns true if one of the checkers processed the node. -// This may return void when all call evaluation logic goes to some checker -// in the future. -bool ExprEngine::CheckerEvalCall(const CallExpr *CE, - ExplodedNodeSet &Dst, - ExplodedNode *Pred) { - bool evaluated = false; - ExplodedNodeSet DstTmp; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { - void *tag = I->first; - Checker *checker = I->second; - - if (checker->GR_evalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) { - evaluated = true; - break; - } else - // The checker didn't evaluate the expr. Restore the DstTmp set. - DstTmp.clear(); - } - - if (evaluated) { - Dst.insert(DstTmp); - return evaluated; - } - - class DefaultEval : public GraphExpander { - bool &Evaluated; - public: - DefaultEval(bool &evaluated) : Evaluated(evaluated) { } - virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { - Evaluated = false; - Dst.insert(Pred); - } - }; - - evaluated = true; - DefaultEval defaultEval(evaluated); - getCheckerManager().runCheckersForEvalCall(Dst, Pred, CE, *this, - &defaultEval); - return evaluated; -} - -// FIXME: This is largely copy-paste from CheckerVisit(). Need to -// unify. -void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst, - ExplodedNodeSet &Src, SVal location, - SVal val, bool isPrevisit) { - - if (Checkers.empty()) { - getCheckerManager().runCheckersForBind(Dst, Src, location, val, StoreE, - *this); - return; - } - - ExplodedNodeSet CheckerV1Tmp; - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &CheckerV1Tmp; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) - checker->GR_VisitBind(*CurrSet, *Builder, *this, StoreE, - *NI, tag, location, val, isPrevisit); - - // Update which NodeSet is the current one. - PrevSet = CurrSet; - } - - getCheckerManager().runCheckersForBind(Dst, CheckerV1Tmp, location, val, - StoreE, *this); - - // Don't autotransition. The CheckerContext objects should do this - // automatically. -} //===----------------------------------------------------------------------===// // Engine construction and deletion. //===----------------------------------------------------------------------===// @@ -333,14 +91,6 @@ ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf) ExprEngine::~ExprEngine() { BR.FlushReports(); delete [] NSExceptionInstanceRaiseSelectors; - - // Delete the set of checkers. - for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I) - delete I->second; - - for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end(); - I!=E;++I) - delete I->second; } //===----------------------------------------------------------------------===// @@ -415,52 +165,6 @@ const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) { /// logic for handling assumptions on symbolic values. const GRState *ExprEngine::processAssume(const GRState *state, SVal cond, bool assumption) { - // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for processing assumptions. This - // can reduce the number of checkers actually called. - CheckersOrdered *CO = &Checkers; - llvm::OwningPtr NewCO; - - CallbackTag K = GetCallbackTag(processAssumeCallback); - CheckersOrdered *& CO_Ref = COCache[K]; - - if (!CO_Ref) { - // If we have no previously cached CheckersOrdered vector for this - // statement kind, then create one. - NewCO.reset(new CheckersOrdered); - } - else { - // Use the already cached set. - CO = CO_Ref; - } - - if (!CO->empty()) { - // Let the checkers have a crack at the assume before the transfer functions - // get their turn. - for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I!=E; ++I) { - - // If any checker declares the state infeasible (or if it starts that - // way), bail out. - if (!state) - return NULL; - - Checker *C = I->second; - bool respondsToCallback = true; - - state = C->evalAssume(state, cond, assumption, &respondsToCallback); - - // Check if we're building the cache of checkers that care about - // assumptions. - if (NewCO.get() && respondsToCallback) - NewCO->push_back(*I); - } - - // If we got through all the checkers, and we built a list of those that - // care about assumptions, save it. - if (NewCO.get()) - CO_Ref = NewCO.take(); - } - state = getCheckerManager().runCheckersForEvalAssume(state, cond, assumption); // If the state is infeasible at this point, bail out. @@ -471,18 +175,6 @@ const GRState *ExprEngine::processAssume(const GRState *state, SVal cond, } bool ExprEngine::wantsRegionChangeUpdate(const GRState* state) { - CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); - CheckersOrdered *CO = COCache[K]; - - if (!CO) - CO = &Checkers; - - for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { - Checker *C = I->second; - if (C->wantsRegionChangeUpdate(state)) - return true; - } - return getCheckerManager().wantsRegionChangeUpdate(state); } @@ -490,60 +182,10 @@ const GRState * ExprEngine::processRegionChanges(const GRState *state, const MemRegion * const *Begin, const MemRegion * const *End) { - // FIXME: Most of this method is copy-pasted from processAssume. - - // Determine if we already have a cached 'CheckersOrdered' vector - // specifically tailored for processing region changes. This - // can reduce the number of checkers actually called. - CheckersOrdered *CO = &Checkers; - llvm::OwningPtr NewCO; - - CallbackTag K = GetCallbackTag(EvalRegionChangesCallback); - CheckersOrdered *& CO_Ref = COCache[K]; - - if (!CO_Ref) { - // If we have no previously cached CheckersOrdered vector for this - // callback, then create one. - NewCO.reset(new CheckersOrdered); - } - else { - // Use the already cached set. - CO = CO_Ref; - } - - // If there are no checkers, just delegate to the checker manager. - if (CO->empty()) - return getCheckerManager().runCheckersForRegionChanges(state, Begin, End); - - for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) { - // If any checker declares the state infeasible (or if it starts that way), - // bail out. - if (!state) - return NULL; - - Checker *C = I->second; - bool respondsToCallback = true; - - state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback); - - // See if we're building a cache of checkers that care about region changes. - if (NewCO.get() && respondsToCallback) - NewCO->push_back(*I); - } - - // If we got through all the checkers, and we built a list of those that - // care about region changes, save it. - if (NewCO.get()) - CO_Ref = NewCO.take(); - return getCheckerManager().runCheckersForRegionChanges(state, Begin, End); } void ExprEngine::processEndWorklist(bool hasWorkRemaining) { - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - I->second->VisitEndAnalysis(G, BR, *this); - } getCheckerManager().runCheckersForEndAnalysis(G, BR, *this); } @@ -585,13 +227,6 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { if (AMgr.shouldPurgeDead()) { const GRState *St = EntryNode->getState(); - - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - Checker *checker = I->second; - checker->MarkLiveSymbols(St, SymReaper); - } - getCheckerManager().runCheckersForLiveSymbols(St, SymReaper); const StackFrameContext *SFC = LC->getCurrentStackFrame(); @@ -617,33 +252,7 @@ void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) { getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode, CleanedState, SymReaper); - ExplodedNodeSet checkersV1Tmp; - if (Checkers.empty()) - checkersV1Tmp.insert(Tmp2); - else { - ExplodedNodeSet Tmp3; - ExplodedNodeSet *SrcSet = &Tmp2; - for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end(); - I != E; ++I) { - ExplodedNodeSet *DstSet = 0; - if (I+1 == E) - DstSet = &checkersV1Tmp; - else { - DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2; - DstSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end(); - NI != NE; ++NI) - checker->GR_evalDeadSymbols(*DstSet, *Builder, *this, currentStmt, - *NI, SymReaper, tag); - SrcSet = DstSet; - } - } - - getCheckerManager().runCheckersForDeadSymbols(Tmp, checkersV1Tmp, + getCheckerManager().runCheckersForDeadSymbols(Tmp, Tmp2, SymReaper, currentStmt, *this); if (!Builder->BuildSinks && !Builder->hasGeneratedNode) @@ -1283,12 +892,6 @@ void ExprEngine::processBranch(const Stmt* Condition, const Stmt* Term, Condition->getLocStart(), "Error evaluating branch"); - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) { - void *tag = I->first; - Checker *checker = I->second; - checker->VisitBranchCondition(builder, *this, Condition, tag); - } - getCheckerManager().runCheckersForBranchCondition(Condition, builder, *this); // If the branch condition is undefined, return; @@ -1413,12 +1016,6 @@ void ExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L, void ExprEngine::processEndOfFunction(EndOfFunctionNodeBuilder& builder) { getTF().evalEndPath(*this, builder); StateMgr.EndPath(builder.getState()); - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){ - void *tag = I->first; - Checker *checker = I->second; - EndOfFunctionNodeBuilder B = builder.withCheckerTag(tag); - checker->evalEndPath(B, tag, *this); - } getCheckerManager().runCheckersForEndPath(builder, *this); } @@ -1638,7 +1235,7 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, ProgramPoint::PostLValueKind); // Post-visit the BlockExpr. - CheckerVisit(BE, Dst, Tmp, PostVisitStmtCallback); + getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); } void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, @@ -1695,7 +1292,7 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* A, ExplodedNodeSet Tmp2; Visit(Idx, *I1, Tmp2); // Evaluate the index. ExplodedNodeSet Tmp3; - CheckerVisit(A, Tmp3, Tmp2, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(Tmp3, Tmp2, A, *this); for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) { const GRState* state = GetState(*I2); @@ -1756,7 +1353,8 @@ void ExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE, // Do a previsit of the bind. ExplodedNodeSet CheckedSet, Src; Src.Add(Pred); - CheckerVisitBind(StoreE, CheckedSet, Src, location, Val, true); + getCheckerManager().runCheckersForBind(CheckedSet, Src, location, Val, StoreE, + *this); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { @@ -1929,53 +1527,23 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, return; } - if (Checkers.empty()) { - ExplodedNodeSet Src; - if (Builder->GetState(Pred) == state) { - Src.Add(Pred); - } else { - // Associate this new state with an ExplodedNode. - Src.Add(Builder->generateNode(S, state, Pred)); - } - getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S, - *this); - return; - } - ExplodedNodeSet Src; - Src.Add(Pred); - ExplodedNodeSet CheckersV1Dst; - ExplodedNodeSet Tmp; - ExplodedNodeSet *PrevSet = &Src; - - for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I) - { - ExplodedNodeSet *CurrSet = 0; - if (I+1 == E) - CurrSet = &CheckersV1Dst; - else { - CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp; - CurrSet->clear(); - } - - void *tag = I->first; - Checker *checker = I->second; - - for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end(); - NI != NE; ++NI) { - // Use the 'state' argument only when the predecessor node is the - // same as Pred. This allows us to catch updates to the state. - checker->GR_visitLocation(*CurrSet, *Builder, *this, S, *NI, - *NI == Pred ? state : GetState(*NI), - location, tag, isLoad); - } - - // Update which NodeSet is the current one. - PrevSet = CurrSet; + if (Builder->GetState(Pred) == state) { + Src.Add(Pred); + } else { + // Associate this new state with an ExplodedNode. + // FIXME: If I pass null tag, the graph is incorrect, e.g for + // int *p; + // p = 0; + // *p = 0xDEADBEEF; + // "p = 0" is not noted as "Null pointer value stored to 'p'" but + // instead "int *p" is noted as + // "Variable 'p' initialized to a null pointer value" + ExplodedNode *N = Builder->generateNode(S, state, Pred, this); + Src.Add(N ? N : Pred); } - - getCheckerManager().runCheckersForLocation(Dst, CheckersV1Dst, location, - isLoad, S, *this); + getCheckerManager().runCheckersForLocation(Dst, Src, location, isLoad, S, + *this); } bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, @@ -2044,58 +1612,59 @@ void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred, ExplodedNodeSet DstTmp2; Visit(Callee, *NI, DstTmp2); // Perform the previsit of the CallExpr, storing the results in DstTmp. - CheckerVisit(CE, DstTmp, DstTmp2, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(DstTmp, DstTmp2, CE, *this); } - // Finally, evaluate the function call. We try each of the checkers - // to see if the can evaluate the function call. - ExplodedNodeSet DstTmp3; - - for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); - DI != DE; ++DI) { - - const GRState* state = GetState(*DI); - SVal L = state->getSVal(Callee); - - // FIXME: Add support for symbolic function calls (calls involving - // function pointer values that are symbolic). - SaveAndRestore OldSink(Builder->BuildSinks); - ExplodedNodeSet DstChecker; - - // If the callee is processed by a checker, skip the rest logic. - if (CheckerEvalCall(CE, DstChecker, *DI)) - DstTmp3.insert(DstChecker); - else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) { - // Callee is inlined. We shouldn't do post call checking. - return; - } - else { - for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(), - DE_Checker = DstChecker.end(); - DI_Checker != DE_Checker; ++DI_Checker) { + class DefaultEval : public GraphExpander { + ExprEngine &Eng; + const CallExpr *CE; + public: + bool Inlined; + + DefaultEval(ExprEngine &eng, const CallExpr *ce) + : Eng(eng), CE(ce), Inlined(false) { } + virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { + if (Eng.getAnalysisManager().shouldInlineCall() && + Eng.InlineCall(Dst, CE, Pred)) { + Inlined = true; + } else { + StmtNodeBuilder &Builder = Eng.getBuilder(); + assert(&Builder && "StmtNodeBuilder must be defined."); // Dispatch to the plug-in transfer function. - unsigned oldSize = DstTmp3.size(); - SaveOr OldHasGen(Builder->hasGeneratedNode); - Pred = *DI_Checker; + unsigned oldSize = Dst.size(); + SaveOr OldHasGen(Builder.hasGeneratedNode); // Dispatch to transfer function logic to handle the call itself. - // FIXME: Allow us to chain together transfer functions. - assert(Builder && "StmtNodeBuilder must be defined."); - getTF().evalCall(DstTmp3, *this, *Builder, CE, L, Pred); + const Expr* Callee = CE->getCallee()->IgnoreParens(); + const GRState* state = Eng.GetState(Pred); + SVal L = state->getSVal(Callee); + Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred); // Handle the case where no nodes where generated. Auto-generate that // contains the updated state if we aren't generating sinks. - if (!Builder->BuildSinks && DstTmp3.size() == oldSize && - !Builder->hasGeneratedNode) - MakeNode(DstTmp3, CE, Pred, state); + if (!Builder.BuildSinks && Dst.size() == oldSize && + !Builder.hasGeneratedNode) + Eng.MakeNode(Dst, CE, Pred, state); } } - } + }; + + // Finally, evaluate the function call. We try each of the checkers + // to see if the can evaluate the function call. + ExplodedNodeSet DstTmp3; + DefaultEval defEval(*this, CE); + + getCheckerManager().runCheckersForEvalCall(DstTmp3, DstTmp, CE, + *this, &defEval); + + // Callee is inlined. We shouldn't do post call checking. + if (defEval.Inlined) + return; // Finally, perform the post-condition check of the CallExpr and store // the created nodes in 'Dst'. - CheckerVisit(CE, Dst, DstTmp3, PostVisitStmtCallback); + getCheckerManager().runCheckersForPostStmt(Dst, DstTmp3, CE, *this); } //===----------------------------------------------------------------------===// @@ -2187,7 +1756,7 @@ void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S, // Pre-visit the ObjCAtSynchronizedStmt. ExplodedNodeSet Tmp; Tmp.Add(Pred); - CheckerVisit(S, Dst, Tmp, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(Dst, Tmp, S, *this); } //===----------------------------------------------------------------------===// @@ -2218,7 +1787,7 @@ void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* Ex, // Perform the post-condition check of the ObjCIvarRefExpr and store // the created nodes in 'Dst'. - CheckerVisit(Ex, Dst, dstIvar, PostVisitStmtCallback); + getCheckerManager().runCheckersForPostStmt(Dst, dstIvar, Ex, *this); } //===----------------------------------------------------------------------===// @@ -2388,7 +1957,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, // Handle the previsits checks. ExplodedNodeSet DstPrevisit; - CheckerVisitObjCMessage(msg, DstPrevisit, Src, /*isPreVisit=*/true); + getCheckerManager().runCheckersForPreObjCMessage(DstPrevisit, Src, msg,*this); // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; @@ -2413,9 +1982,9 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, llvm::tie(notNilState, nilState) = state->assume(receiverVal); // There are three cases: can be nil or non-nil, must be nil, must be - // non-nil. We handle must be nil, and merge the rest two into non-nil. + // non-nil. We ignore must be nil, and merge the rest two into non-nil. if (nilState && !notNilState) { - CheckerEvalNilReceiver(msg, dstEval, nilState, Pred); + dstEval.insert(Pred); continue; } @@ -2491,7 +2060,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessage &msg, // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. - CheckerVisitObjCMessage(msg, Dst, dstEval, /*isPreVisit=*/false); + getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this); } //===----------------------------------------------------------------------===// @@ -2504,7 +2073,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNodeSet S1; Visit(Ex, Pred, S1); ExplodedNodeSet S2; - CheckerVisit(CastE, S2, S1, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(S2, S1, CastE, *this); if (CastE->getCastKind() == CK_LValueToRValue || CastE->getCastKind() == CK_GetObjCProperty) { @@ -2677,7 +2246,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Tmp.Add(Pred); ExplodedNodeSet Tmp2; - CheckerVisit(DS, Tmp2, Tmp, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(Tmp2, Tmp, DS, *this); for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) { ExplodedNode *N = *I; @@ -3238,7 +2807,7 @@ void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, } ExplodedNodeSet CheckedSet; - CheckerVisit(RS, CheckedSet, Src, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(CheckedSet, Src, RS, *this); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) { @@ -3280,7 +2849,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, Visit(RHS, *I1, Tmp2); ExplodedNodeSet CheckedSet; - CheckerVisit(B, CheckedSet, Tmp2, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(CheckedSet, Tmp2, B, *this); // With both the LHS and RHS evaluated, process the operation itself. @@ -3407,16 +2976,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, } } - CheckerVisit(B, Dst, Tmp3, PostVisitStmtCallback); -} - -//===----------------------------------------------------------------------===// -// Checker registration/lookup. -//===----------------------------------------------------------------------===// - -Checker *ExprEngine::lookupChecker(void *tag) const { - CheckerMap::const_iterator I = CheckerM.find(tag); - return (I == CheckerM.end()) ? NULL : Checkers[I->second].second; + getCheckerManager().runCheckersForPostStmt(Dst, Tmp3, B, *this); } //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp index b3721d7659..5005f79af2 100644 --- a/lib/StaticAnalyzer/Core/CFRefCount.cpp +++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp @@ -12,6 +12,9 @@ // //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/CheckerV2.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/LangOptions.h" @@ -20,7 +23,6 @@ #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngineBuilders.h" #include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" @@ -3395,19 +3397,15 @@ void CFRefCount::ProcessNonLeakError(ExplodedNodeSet& Dst, namespace { class RetainReleaseChecker - : public CheckerVisitor { - CFRefCount *TF; + : public CheckerV2< check::PostStmt > { public: - RetainReleaseChecker(CFRefCount *tf) : TF(tf) {} - static void* getTag() { static int x = 0; return &x; } - - void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE); + void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; }; } // end anonymous namespace -void RetainReleaseChecker::PostVisitBlockExpr(CheckerContext &C, - const BlockExpr *BE) { +void RetainReleaseChecker::checkPostStmt(const BlockExpr *BE, + CheckerContext &C) const { // Scan the BlockDecRefExprs for any object the retain/release checker // may be tracking. @@ -3510,7 +3508,9 @@ void CFRefCount::RegisterChecks(ExprEngine& Eng) { // Register the RetainReleaseChecker with the ExprEngine object. // Functionality in CFRefCount will be migrated to RetainReleaseChecker // over time. - Eng.registerCheck(new RetainReleaseChecker(this)); + // FIXME: HACK! Remove TransferFuncs and turn all of CFRefCount into fully + // using the checker mechanism. + Eng.getCheckerManager().registerChecker(); } TransferFuncs* ento::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, diff --git a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp index 56dfe8cb04..7d8a22bf2b 100644 --- a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/AST/DeclCXX.h" @@ -224,11 +225,11 @@ void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD, ExplodedNodeSet &Src, ExplodedNodeSet &Dst) { // Allow checkers to pre-visit the member call. ExplodedNodeSet PreVisitChecks; - CheckerVisit(MCE, PreVisitChecks, Src, PreVisitStmtCallback); + getCheckerManager().runCheckersForPreStmt(PreVisitChecks, Src, MCE, *this); if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) { // FIXME: conservative method call evaluation. - CheckerVisit(MCE, Dst, PreVisitChecks, PostVisitStmtCallback); + getCheckerManager().runCheckersForPostStmt(Dst, PreVisitChecks, MCE, *this); return; }