diff options
-rw-r--r-- | include/clang/StaticAnalyzer/Core/Checker.h | 59 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/CheckerManager.h | 26 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp | 36 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CheckerManager.cpp | 57 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 11 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 15 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineObjC.cpp | 21 |
7 files changed, 197 insertions, 28 deletions
diff --git a/include/clang/StaticAnalyzer/Core/Checker.h b/include/clang/StaticAnalyzer/Core/Checker.h index 07a1ccff6c..3214d96c53 100644 --- a/include/clang/StaticAnalyzer/Core/Checker.h +++ b/include/clang/StaticAnalyzer/Core/Checker.h @@ -150,6 +150,36 @@ public: } }; +class PreCall { + template <typename CHECKER> + static void _checkCall(void *checker, const CallEvent &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkPreCall(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPreCall( + CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>)); + } +}; + +class PostCall { + template <typename CHECKER> + static void _checkCall(void *checker, const CallEvent &msg, + CheckerContext &C) { + ((const CHECKER *)checker)->checkPostCall(msg, C); + } + +public: + template <typename CHECKER> + static void _register(CHECKER *checker, CheckerManager &mgr) { + mgr._registerForPostCall( + CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>)); + } +}; + class Location { template <typename CHECKER> static void _checkLocation(void *checker, @@ -372,16 +402,14 @@ template <typename CHECK1, typename CHECK2=check::_VoidCheck, typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck, typename CHECK13=check::_VoidCheck,typename CHECK14=check::_VoidCheck, typename CHECK15=check::_VoidCheck,typename CHECK16=check::_VoidCheck, - typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck> + typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck, + typename CHECK19=check::_VoidCheck,typename CHECK20=check::_VoidCheck, + typename CHECK21=check::_VoidCheck,typename CHECK22=check::_VoidCheck, + typename CHECK23=check::_VoidCheck,typename CHECK24=check::_VoidCheck> class Checker; template <> -class Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, - check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, - check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, - check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, - check::_VoidCheck, check::_VoidCheck, check::_VoidCheck, - check::_VoidCheck, check::_VoidCheck, check::_VoidCheck> +class Checker<check::_VoidCheck> : public CheckerBase { virtual void anchor(); @@ -393,19 +421,22 @@ template <typename CHECK1, typename CHECK2, typename CHECK3, typename CHECK4, typename CHECK5, typename CHECK6, typename CHECK7, typename CHECK8, typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12, typename CHECK13,typename CHECK14,typename CHECK15,typename CHECK16, - typename CHECK17,typename CHECK18> + typename CHECK17,typename CHECK18,typename CHECK19,typename CHECK20, + typename CHECK21,typename CHECK22,typename CHECK23,typename CHECK24> class Checker : public CHECK1, - public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8, - CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15, - CHECK16,CHECK17,CHECK18> { + public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, + CHECK8, CHECK9, CHECK10,CHECK11,CHECK12,CHECK13, + CHECK14,CHECK15,CHECK16,CHECK17,CHECK18,CHECK19, + CHECK20,CHECK21,CHECK22,CHECK23,CHECK24> { public: template <typename CHECKER> static void _register(CHECKER *checker, CheckerManager &mgr) { CHECK1::_register(checker, mgr); - Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8, - CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15, - CHECK16,CHECK17,CHECK18>::_register(checker, mgr); + Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, + CHECK8, CHECK9, CHECK10,CHECK11,CHECK12,CHECK13, + CHECK14,CHECK15,CHECK16,CHECK17,CHECK18,CHECK19, + CHECK20,CHECK21,CHECK22,CHECK23,CHECK24>::_register(checker, mgr); } }; diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h index 689b13d99d..7e1b07a584 100644 --- a/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -221,6 +221,23 @@ public: const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng); + /// \brief Run checkers for pre-visiting obj-c messages. + void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, + const CallEvent &Call, ExprEngine &Eng) { + runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng); + } + + /// \brief Run checkers for post-visiting obj-c messages. + void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, + const CallEvent &Call, ExprEngine &Eng) { + runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng); + } + + /// \brief Run checkers for visiting obj-c messages. + void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const CallEvent &Call, ExprEngine &Eng); + /// \brief Run checkers for load/store of a location. void runCheckersForLocation(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, @@ -339,6 +356,9 @@ public: typedef CheckerFn<void (const ObjCMethodCall &, CheckerContext &)> CheckObjCMessageFunc; + + typedef CheckerFn<void (const CallEvent &, CheckerContext &)> + CheckCallFunc; typedef CheckerFn<void (const SVal &location, bool isLoad, const Stmt *S, @@ -397,6 +417,9 @@ public: void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); + void _registerForPreCall(CheckCallFunc checkfn); + void _registerForPostCall(CheckCallFunc checkfn); + void _registerForLocation(CheckLocationFunc checkfn); void _registerForBind(CheckBindFunc checkfn); @@ -518,6 +541,9 @@ private: std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers; std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers; + std::vector<CheckCallFunc> PreCallCheckers; + std::vector<CheckCallFunc> PostCallCheckers; + std::vector<CheckLocationFunc> LocationCheckers; std::vector<CheckBindFunc> BindCheckers; diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp index 751b8f4c89..842cbc5f59 100644 --- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp @@ -37,6 +37,8 @@ class CheckerDocumentation : public Checker< check::PreStmt<DeclStmt>, check::PostStmt<CallExpr>, check::PreObjCMessage, check::PostObjCMessage, + check::PreCall, + check::PostCall, check::BranchCondition, check::Location, check::Bind, @@ -72,15 +74,43 @@ public: /// which does not include the control flow statements such as IfStmt. The /// callback can be specialized to be called with any subclass of Stmt. /// - /// check::PostStmt<DeclStmt> + /// check::PostStmt<CallExpr> void checkPostStmt(const CallExpr *DS, CheckerContext &C) const; - /// \brief Pre-visit the Objective C messages. + /// \brief Pre-visit the Objective C message. + /// + /// This will be called before the analyzer core processes the method call. + /// This is called for any action which produces an Objective-C message send, + /// including explicit message syntax and property access. See the subclasses + /// of ObjCMethodCall for more details. + /// + /// check::PreObjCMessage void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const {} - /// \brief Post-visit the Objective C messages. + /// \brief Post-visit the Objective C message. + /// \sa checkPreObjCMessage() + /// + /// check::PostObjCMessage void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const {} + /// \brief Pre-visit an abstract "call" event. + /// + /// This is used for checkers that want to check arguments or attributed + /// behavior for functions and methods no matter how they are being invoked. + /// + /// Note that this includes ALL cross-body invocations, so if you want to + /// limit your checks to, say, function calls, you can either test for that + /// or fall back to the explicit callback (i.e. check::PreStmt). + /// + /// check::PreCall + void checkPreCall(const CallEvent &Call, CheckerContext &C) const {} + + /// \brief Post-visit an abstract "call" event. + /// \sa checkPreObjCMessage() + /// + /// check::PostCall + void checkPostCall(const CallEvent &Call, CheckerContext &C) const {} + /// \brief Pre-visit of the condition statement of a branch (such as IfStmt). void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const {} diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index e4209e50b3..39a3621826 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -25,6 +25,8 @@ bool CheckerManager::hasPathSensitiveCheckers() const { return !StmtCheckers.empty() || !PreObjCMessageCheckers.empty() || !PostObjCMessageCheckers.empty() || + !PreCallCheckers.empty() || + !PostCallCheckers.empty() || !LocationCheckers.empty() || !BindCheckers.empty() || !EndAnalysisCheckers.empty() || @@ -217,6 +219,54 @@ void CheckerManager::runCheckersForObjCMessage(bool isPreVisit, } namespace { + // FIXME: This has all the same signatures as CheckObjCMessageContext. + // Is there a way we can merge the two? + struct CheckCallContext { + typedef std::vector<CheckerManager::CheckCallFunc> CheckersTy; + bool IsPreVisit; + const CheckersTy &Checkers; + const CallEvent &Call; + ExprEngine &Eng; + + CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } + CheckersTy::const_iterator checkers_end() { return Checkers.end(); } + + CheckCallContext(bool isPreVisit, const CheckersTy &checkers, + const CallEvent &call, ExprEngine &eng) + : IsPreVisit(isPreVisit), Checkers(checkers), Call(call), Eng(eng) { } + + void runChecker(CheckerManager::CheckCallFunc checkFn, + NodeBuilder &Bldr, ExplodedNode *Pred) { + // FIXME: This will be wrong as soon as we handle any calls without + // associated statements. + ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind + : ProgramPoint::PostStmtKind; + assert(Call.getOriginExpr() && "Calls without stmts not yet handled"); + const ProgramPoint &L = + ProgramPoint::getProgramPoint(Call.getOriginExpr(), + K, Pred->getLocationContext(), + checkFn.Checker); + CheckerContext C(Bldr, Eng, Pred, L); + + checkFn(Call, C); + } + }; +} + +/// \brief Run checkers for visiting an abstract call event. +void CheckerManager::runCheckersForCallEvent(bool isPreVisit, + ExplodedNodeSet &Dst, + const ExplodedNodeSet &Src, + const CallEvent &Call, + ExprEngine &Eng) { + CheckCallContext C(isPreVisit, + isPreVisit ? PreCallCheckers + : PostCallCheckers, + Call, Eng); + expandGraphWithCheckers(C, Dst, Src); +} + +namespace { struct CheckLocationContext { typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy; const CheckersTy &Checkers; @@ -584,6 +634,13 @@ void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) { PostObjCMessageCheckers.push_back(checkfn); } +void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) { + PreCallCheckers.push_back(checkfn); +} +void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) { + PostCallCheckers.push_back(checkfn); +} + void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) { LocationCheckers.push_back(checkfn); } diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 45310dc6c6..88dac4c8c8 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -55,14 +55,19 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNodeSet DstPreVisit; getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this); + ExplodedNodeSet DstPreCall; + getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit, + Call, *this); ExplodedNodeSet DstInvalidated; - for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), E = DstPreVisit.end(); + for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(DstInvalidated, *I, Call); - getCheckerManager().runCheckersForPostStmt(destNodes, DstInvalidated, - CE, *this); + ExplodedNodeSet DstPostCall; + getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated, + Call, *this); + getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this); } void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index d2d2f53eaf..3761f9c10a 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -359,7 +359,20 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred, void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, const SimpleCall &Call) { - getCheckerManager().runCheckersForEvalCall(Dst, Pred, Call, *this); + // Run any pre-call checks using the generic call interface. + ExplodedNodeSet dstPreVisit; + getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, Call, *this); + + // Actually evaluate the function call. We try each of the checkers + // to see if the can evaluate the function call, and get a callback at + // defaultEvalCall if all of them fail. + ExplodedNodeSet dstCallEvaluated; + getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit, + Call, *this); + + // Finally, run any post-call checks. + getCheckerManager().runCheckersForPostCall(Dst, dstCallEvaluated, + Call, *this); } void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index 5444b74dfb..f99fe5ff37 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -146,15 +146,18 @@ void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg, // Handle the previsits checks. ExplodedNodeSet dstPrevisit; - getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, + getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred, msg, *this); - + ExplodedNodeSet dstGenericPrevisit; + getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit, + msg, *this); + // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; - StmtNodeBuilder Bldr(dstPrevisit, dstEval, *currentBuilderContext); + StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext); - for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(), - DE = dstPrevisit.end(); DI != DE; ++DI) { + for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(), + DE = dstGenericPrevisit.end(); DI != DE; ++DI) { ExplodedNode *Pred = *DI; bool RaisesException = false; @@ -235,9 +238,13 @@ void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg, } } + ExplodedNodeSet dstPostvisit; + getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, msg, *this); + // Finally, perform the post-condition check of the ObjCMessageExpr and store // the created nodes in 'Dst'. - getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this); + getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit, + msg, *this); } void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr, @@ -280,7 +287,7 @@ void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr, state = msg.invalidateRegions(BlockCount, state); // And create the new node. - Bldr.generateNode(msg.getOriginExpr(), Pred, state, GenSink); + Bldr.generateNode(currentStmt, Pred, state, GenSink); assert(Bldr.hasGeneratedNodes()); } |