//===--- CheckerManager.h - Static Analyzer Checker Manager -----*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // Defines the Static Analyzer Checker Manager. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SA_CORE_CHECKERMANAGER_H #define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H #include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/LangOptions.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include namespace clang { class Decl; class Stmt; class CallExpr; namespace ento { class CheckerBase; class ExprEngine; class AnalysisManager; class BugReporter; class CheckerContext; class SimpleCall; class ObjCMethodCall; class SVal; class ExplodedNode; class ExplodedNodeSet; class ExplodedGraph; class ProgramState; class NodeBuilder; struct NodeBuilderContext; class MemRegion; class SymbolReaper; template class CheckerFn; template class CheckerFn { typedef RET (*Func)(void *, P1, P2, P3, P4, P5); Func Fn; public: CheckerBase *Checker; CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) const { return Fn(Checker, p1, p2, p3, p4, p5); } }; template class CheckerFn { typedef RET (*Func)(void *, P1, P2, P3, P4); Func Fn; public: CheckerBase *Checker; CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()(P1 p1, P2 p2, P3 p3, P4 p4) const { return Fn(Checker, p1, p2, p3, p4); } }; template class CheckerFn { typedef RET (*Func)(void *, P1, P2, P3); Func Fn; public: CheckerBase *Checker; CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()(P1 p1, P2 p2, P3 p3) const { return Fn(Checker, p1, p2, p3); } }; template class CheckerFn { typedef RET (*Func)(void *, P1, P2); Func Fn; public: CheckerBase *Checker; CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()(P1 p1, P2 p2) const { return Fn(Checker, p1, p2); } }; template class CheckerFn { typedef RET (*Func)(void *, P1); Func Fn; public: CheckerBase *Checker; CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()(P1 p1) const { return Fn(Checker, p1); } }; template class CheckerFn { typedef RET (*Func)(void *); Func Fn; public: CheckerBase *Checker; CheckerFn(CheckerBase *checker, Func fn) : Fn(fn), Checker(checker) { } RET operator()() const { return Fn(Checker); } }; /// \brief Describes the different reasons a pointer escapes /// during analysis. enum PointerEscapeKind { /// A pointer escapes due to binding its value to a location /// that the analyzer cannot track. PSK_EscapeOnBind, /// The pointer has been passed to a function call directly. PSK_DirectEscapeOnCall, /// The pointer has been passed to a function indirectly. /// For example, the pointer is accessible through an /// argument to a function. PSK_IndirectEscapeOnCall, /// The reason for pointer escape is unknown. For example, /// a region containing this pointer is invalidated. PSK_EscapeOther }; class CheckerManager { const LangOptions LangOpts; AnalyzerOptionsRef AOptions; public: CheckerManager(const LangOptions &langOpts, AnalyzerOptionsRef AOptions) : LangOpts(langOpts), AOptions(AOptions) {} ~CheckerManager(); bool hasPathSensitiveCheckers() const; void finishedCheckerRegistration(); const LangOptions &getLangOpts() const { return LangOpts; } AnalyzerOptions &getAnalyzerOptions() { return *AOptions; } typedef CheckerBase *CheckerRef; typedef const void *CheckerTag; typedef CheckerFn CheckerDtor; //===----------------------------------------------------------------------===// // registerChecker //===----------------------------------------------------------------------===// /// \brief Used to register checkers. /// /// \returns a pointer to the checker object. template CHECKER *registerChecker() { CheckerTag tag = getTag(); CheckerRef &ref = CheckerTags[tag]; if (ref) return static_cast(ref); // already registered. CHECKER *checker = new CHECKER(); CheckerDtors.push_back(CheckerDtor(checker, destruct)); CHECKER::_register(checker, *this); ref = checker; return checker; } template CHECKER *registerChecker(AnalyzerOptions &AOpts) { CheckerTag tag = getTag(); CheckerRef &ref = CheckerTags[tag]; if (ref) return static_cast(ref); // already registered. CHECKER *checker = new CHECKER(AOpts); CheckerDtors.push_back(CheckerDtor(checker, destruct)); CHECKER::_register(checker, *this); ref = checker; return checker; } //===----------------------------------------------------------------------===// // Functions for running checkers for AST traversing.. //===----------------------------------------------------------------------===// /// \brief Run checkers handling Decls. void runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, BugReporter &BR); /// \brief Run checkers handling Decls containing a Stmt body. void runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR); //===----------------------------------------------------------------------===// // Functions for running checkers for path-sensitive checking. //===----------------------------------------------------------------------===// /// \brief Run checkers for pre-visiting Stmts. /// /// The notification is performed for every explored CFGElement, which does /// not include the control flow statements such as IfStmt. /// /// \sa runCheckersForBranchCondition, runCheckersForPostStmt void runCheckersForPreStmt(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng) { runCheckersForStmt(/*isPreVisit=*/true, Dst, Src, S, Eng); } /// \brief Run checkers for post-visiting Stmts. /// /// The notification is performed for every explored CFGElement, which does /// not include the control flow statements such as IfStmt. /// /// \sa runCheckersForBranchCondition, runCheckersForPreStmt void runCheckersForPostStmt(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng, bool wasInlined = false) { runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng, wasInlined); } /// \brief Run checkers for visiting Stmts. void runCheckersForStmt(bool isPreVisit, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const Stmt *S, ExprEngine &Eng, bool wasInlined = false); /// \brief Run checkers for pre-visiting obj-c messages. void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng) { runCheckersForObjCMessage(/*isPreVisit=*/true, Dst, Src, msg, Eng); } /// \brief Run checkers for post-visiting obj-c messages. void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng, bool wasInlined = false) { runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng, wasInlined); } /// \brief Run checkers for visiting obj-c messages. void runCheckersForObjCMessage(bool isPreVisit, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const ObjCMethodCall &msg, ExprEngine &Eng, bool wasInlined = false); /// \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, bool wasInlined = false) { runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng, wasInlined); } /// \brief Run checkers for visiting obj-c messages. void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &Call, ExprEngine &Eng, bool wasInlined = false); /// \brief Run checkers for load/store of a location. void runCheckersForLocation(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SVal location, bool isLoad, const Stmt *NodeEx, const Stmt *BoundEx, ExprEngine &Eng); /// \brief Run checkers for binding of a value to a location. void runCheckersForBind(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SVal location, SVal val, const Stmt *S, ExprEngine &Eng, const ProgramPoint &PP); /// \brief Run checkers for end of analysis. void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng); /// \brief Run checkers on end of function. void runCheckersForEndFunction(NodeBuilderContext &BC, ExplodedNodeSet &Dst, ExplodedNode *Pred, ExprEngine &Eng); /// \brief Run checkers for branch condition. void runCheckersForBranchCondition(const Stmt *condition, ExplodedNodeSet &Dst, ExplodedNode *Pred, ExprEngine &Eng); /// \brief Run checkers for live symbols. /// /// Allows modifying SymbolReaper object. For example, checkers can explicitly /// register symbols of interest as live. These symbols will not be marked /// dead and removed. void runCheckersForLiveSymbols(ProgramStateRef state, SymbolReaper &SymReaper); /// \brief Run checkers for dead symbols. /// /// Notifies checkers when symbols become dead. For example, this allows /// checkers to aggressively clean up/reduce the checker state and produce /// precise diagnostics. void runCheckersForDeadSymbols(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SymbolReaper &SymReaper, const Stmt *S, ExprEngine &Eng, ProgramPoint::Kind K); /// \brief True if at least one checker wants to check region changes. bool wantsRegionChangeUpdate(ProgramStateRef state); /// \brief Run checkers for region changes. /// /// This corresponds to the check::RegionChanges callback. /// \param state The current program state. /// \param invalidated A set of all symbols potentially touched by the change. /// \param ExplicitRegions The regions explicitly requested for invalidation. /// For example, in the case of a function call, these would be arguments. /// \param Regions The transitive closure of accessible regions, /// i.e. all regions that may have been touched by this change. /// \param Call The call expression wrapper if the regions are invalidated /// by a call. ProgramStateRef runCheckersForRegionChanges(ProgramStateRef state, const InvalidatedSymbols *invalidated, ArrayRef ExplicitRegions, ArrayRef Regions, const CallEvent *Call); /// \brief Run checkers when pointers escape. /// /// This notifies the checkers about pointer escape, which occurs whenever /// the analyzer cannot track the symbol any more. For example, as a /// result of assigning a pointer into a global or when it's passed to a /// function call the analyzer cannot model. /// /// \param State The state at the point of escape. /// \param Escaped The list of escaped symbols. /// \param Call The corresponding CallEvent, if the symbols escape as /// parameters to the given call. /// \param Kind The reason of pointer escape. /// \param ITraits Information about invalidation for a particular /// region/symbol. /// \returns Checkers can modify the state by returning a new one. ProgramStateRef runCheckersForPointerEscape(ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, RegionAndSymbolInvalidationTraits *ITraits); /// \brief Run checkers for handling assumptions on symbolic values. ProgramStateRef runCheckersForEvalAssume(ProgramStateRef state, SVal Cond, bool Assumption); /// \brief Run checkers for evaluating a call. /// /// Warning: Currently, the CallEvent MUST come from a CallExpr! void runCheckersForEvalCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, const CallEvent &CE, ExprEngine &Eng); /// \brief Run checkers for the entire Translation Unit. void runCheckersOnEndOfTranslationUnit(const TranslationUnitDecl *TU, AnalysisManager &mgr, BugReporter &BR); /// \brief Run checkers for debug-printing a ProgramState. /// /// Unlike most other callbacks, any checker can simply implement the virtual /// method CheckerBase::printState if it has custom data to print. /// \param Out The output stream /// \param State The state being printed /// \param NL The preferred representation of a newline. /// \param Sep The preferred separator between different kinds of data. void runCheckersForPrintState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep); //===----------------------------------------------------------------------===// // Internal registration functions for AST traversing. //===----------------------------------------------------------------------===// // Functions used by the registration mechanism, checkers should not touch // these directly. typedef CheckerFn CheckDeclFunc; typedef bool (*HandlesDeclFunc)(const Decl *D); void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn); void _registerForBody(CheckDeclFunc checkfn); //===----------------------------------------------------------------------===// // Internal registration functions for path-sensitive checking. //===----------------------------------------------------------------------===// typedef CheckerFn CheckStmtFunc; typedef CheckerFn CheckObjCMessageFunc; typedef CheckerFn CheckCallFunc; typedef CheckerFn CheckLocationFunc; typedef CheckerFn CheckBindFunc; typedef CheckerFn CheckEndAnalysisFunc; typedef CheckerFn CheckEndFunctionFunc; typedef CheckerFn CheckBranchConditionFunc; typedef CheckerFn CheckDeadSymbolsFunc; typedef CheckerFn CheckLiveSymbolsFunc; typedef CheckerFn ExplicitRegions, ArrayRef Regions, const CallEvent *Call)> CheckRegionChangesFunc; typedef CheckerFn WantsRegionChangeUpdateFunc; typedef CheckerFn CheckPointerEscapeFunc; typedef CheckerFn EvalAssumeFunc; typedef CheckerFn EvalCallFunc; typedef CheckerFn CheckEndOfTranslationUnit; typedef bool (*HandlesStmtFunc)(const Stmt *D); void _registerForPreStmt(CheckStmtFunc checkfn, HandlesStmtFunc isForStmtFn); void _registerForPostStmt(CheckStmtFunc checkfn, HandlesStmtFunc isForStmtFn); void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn); void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn); void _registerForPreCall(CheckCallFunc checkfn); void _registerForPostCall(CheckCallFunc checkfn); void _registerForLocation(CheckLocationFunc checkfn); void _registerForBind(CheckBindFunc checkfn); void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn); void _registerForEndFunction(CheckEndFunctionFunc checkfn); void _registerForBranchCondition(CheckBranchConditionFunc checkfn); void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn); void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn); void _registerForRegionChanges(CheckRegionChangesFunc checkfn, WantsRegionChangeUpdateFunc wantUpdateFn); void _registerForPointerEscape(CheckPointerEscapeFunc checkfn); void _registerForConstPointerEscape(CheckPointerEscapeFunc checkfn); void _registerForEvalAssume(EvalAssumeFunc checkfn); void _registerForEvalCall(EvalCallFunc checkfn); void _registerForEndOfTranslationUnit(CheckEndOfTranslationUnit checkfn); //===----------------------------------------------------------------------===// // Internal registration functions for events. //===----------------------------------------------------------------------===// typedef void *EventTag; typedef CheckerFn CheckEventFunc; template void _registerListenerForEvent(CheckEventFunc checkfn) { EventInfo &info = Events[getTag()]; info.Checkers.push_back(checkfn); } template void _registerDispatcherForEvent() { EventInfo &info = Events[getTag()]; info.HasDispatcher = true; } template void _dispatchEvent(const EVENT &event) const { EventsTy::const_iterator I = Events.find(getTag()); if (I == Events.end()) return; const EventInfo &info = I->second; for (unsigned i = 0, e = info.Checkers.size(); i != e; ++i) info.Checkers[i](&event); } //===----------------------------------------------------------------------===// // Implementation details. //===----------------------------------------------------------------------===// private: template static void destruct(void *obj) { delete static_cast(obj); } template static void *getTag() { static int tag; return &tag; } llvm::DenseMap CheckerTags; std::vector CheckerDtors; struct DeclCheckerInfo { CheckDeclFunc CheckFn; HandlesDeclFunc IsForDeclFn; }; std::vector DeclCheckers; std::vector BodyCheckers; typedef SmallVector CachedDeclCheckers; typedef llvm::DenseMap CachedDeclCheckersMapTy; CachedDeclCheckersMapTy CachedDeclCheckersMap; struct StmtCheckerInfo { CheckStmtFunc CheckFn; HandlesStmtFunc IsForStmtFn; bool IsPreVisit; }; std::vector StmtCheckers; typedef SmallVector CachedStmtCheckers; typedef llvm::DenseMap CachedStmtCheckersMapTy; CachedStmtCheckersMapTy CachedStmtCheckersMap; const CachedStmtCheckers &getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit); std::vector PreObjCMessageCheckers; std::vector PostObjCMessageCheckers; std::vector PreCallCheckers; std::vector PostCallCheckers; std::vector LocationCheckers; std::vector BindCheckers; std::vector EndAnalysisCheckers; std::vector EndFunctionCheckers; std::vector BranchConditionCheckers; std::vector LiveSymbolsCheckers; std::vector DeadSymbolsCheckers; struct RegionChangesCheckerInfo { CheckRegionChangesFunc CheckFn; WantsRegionChangeUpdateFunc WantUpdateFn; }; std::vector RegionChangesCheckers; std::vector PointerEscapeCheckers; std::vector EvalAssumeCheckers; std::vector EvalCallCheckers; std::vector EndOfTranslationUnitCheckers; struct EventInfo { SmallVector Checkers; bool HasDispatcher; EventInfo() : HasDispatcher(false) { } }; typedef llvm::DenseMap EventsTy; EventsTy Events; }; } // end ento namespace } // end clang namespace #endif