//== Checker.h - Registration mechanism for checkers -------------*- C++ -*--=// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file defines Checker, used to create and register checkers. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_SA_CORE_CHECKER #define LLVM_CLANG_SA_CORE_CHECKER #include "clang/Analysis/ProgramPoint.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/Support/Casting.h" namespace clang { namespace ento { class BugReporter; namespace check { struct _VoidCheck { static void _register(void *checker, CheckerManager &mgr) { } }; template class ASTDecl { template static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr, BugReporter &BR) { ((const CHECKER *)checker)->checkASTDecl(cast(D), mgr, BR); } static bool _handlesDecl(const Decl *D) { return isa(D); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForDecl(CheckerManager::CheckDeclFunc(checker, _checkDecl), _handlesDecl); } }; class ASTCodeBody { template static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr, BugReporter &BR) { ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForBody(CheckerManager::CheckDeclFunc(checker, _checkBody)); } }; class EndOfTranslationUnit { template static void _checkEndOfTranslationUnit(void *checker, const TranslationUnitDecl *TU, AnalysisManager& mgr, BugReporter &BR) { ((const CHECKER *)checker)->checkEndOfTranslationUnit(TU, mgr, BR); } public: template static void _register(CHECKER *checker, CheckerManager &mgr){ mgr._registerForEndOfTranslationUnit( CheckerManager::CheckEndOfTranslationUnit(checker, _checkEndOfTranslationUnit)); } }; template class PreStmt { template static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { ((const CHECKER *)checker)->checkPreStmt(cast(S), C); } static bool _handlesStmt(const Stmt *S) { return isa(S); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForPreStmt(CheckerManager::CheckStmtFunc(checker, _checkStmt), _handlesStmt); } }; template class PostStmt { template static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { ((const CHECKER *)checker)->checkPostStmt(cast(S), C); } static bool _handlesStmt(const Stmt *S) { return isa(S); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForPostStmt(CheckerManager::CheckStmtFunc(checker, _checkStmt), _handlesStmt); } }; class PreObjCMessage { template static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, CheckerContext &C) { ((const CHECKER *)checker)->checkPreObjCMessage(msg, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForPreObjCMessage( CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage)); } }; class PostObjCMessage { template static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, CheckerContext &C) { ((const CHECKER *)checker)->checkPostObjCMessage(msg, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForPostObjCMessage( CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage)); } }; class PreCall { template static void _checkCall(void *checker, const CallEvent &msg, CheckerContext &C) { ((const CHECKER *)checker)->checkPreCall(msg, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForPreCall( CheckerManager::CheckCallFunc(checker, _checkCall)); } }; class PostCall { template static void _checkCall(void *checker, const CallEvent &msg, CheckerContext &C) { ((const CHECKER *)checker)->checkPostCall(msg, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForPostCall( CheckerManager::CheckCallFunc(checker, _checkCall)); } }; class Location { template static void _checkLocation(void *checker, const SVal &location, bool isLoad, const Stmt *S, CheckerContext &C) { ((const CHECKER *)checker)->checkLocation(location, isLoad, S, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForLocation( CheckerManager::CheckLocationFunc(checker, _checkLocation)); } }; class Bind { template static void _checkBind(void *checker, const SVal &location, const SVal &val, const Stmt *S, CheckerContext &C) { ((const CHECKER *)checker)->checkBind(location, val, S, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForBind( CheckerManager::CheckBindFunc(checker, _checkBind)); } }; class EndAnalysis { template static void _checkEndAnalysis(void *checker, ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng) { ((const CHECKER *)checker)->checkEndAnalysis(G, BR, Eng); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForEndAnalysis( CheckerManager::CheckEndAnalysisFunc(checker, _checkEndAnalysis)); } }; class EndFunction { template static void _checkEndFunction(void *checker, CheckerContext &C) { ((const CHECKER *)checker)->checkEndFunction(C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForEndFunction( CheckerManager::CheckEndFunctionFunc(checker, _checkEndFunction)); } }; class BranchCondition { template static void _checkBranchCondition(void *checker, const Stmt *Condition, CheckerContext & C) { ((const CHECKER *)checker)->checkBranchCondition(Condition, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForBranchCondition( CheckerManager::CheckBranchConditionFunc(checker, _checkBranchCondition)); } }; class LiveSymbols { template static void _checkLiveSymbols(void *checker, ProgramStateRef state, SymbolReaper &SR) { ((const CHECKER *)checker)->checkLiveSymbols(state, SR); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForLiveSymbols( CheckerManager::CheckLiveSymbolsFunc(checker, _checkLiveSymbols)); } }; class DeadSymbols { template static void _checkDeadSymbols(void *checker, SymbolReaper &SR, CheckerContext &C) { ((const CHECKER *)checker)->checkDeadSymbols(SR, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForDeadSymbols( CheckerManager::CheckDeadSymbolsFunc(checker, _checkDeadSymbols)); } }; class RegionChanges { template static ProgramStateRef _checkRegionChanges(void *checker, ProgramStateRef state, const InvalidatedSymbols *invalidated, ArrayRef Explicits, ArrayRef Regions, const CallEvent *Call) { return ((const CHECKER *)checker)->checkRegionChanges(state, invalidated, Explicits, Regions, Call); } template static bool _wantsRegionChangeUpdate(void *checker, ProgramStateRef state) { return ((const CHECKER *)checker)->wantsRegionChangeUpdate(state); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForRegionChanges( CheckerManager::CheckRegionChangesFunc(checker, _checkRegionChanges), CheckerManager::WantsRegionChangeUpdateFunc(checker, _wantsRegionChangeUpdate)); } }; class PointerEscape { template static ProgramStateRef _checkPointerEscape(void *Checker, ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, RegionAndSymbolInvalidationTraits *ETraits) { if (!ETraits) return ((const CHECKER *)Checker)->checkPointerEscape(State, Escaped, Call, Kind); InvalidatedSymbols RegularEscape; for (InvalidatedSymbols::const_iterator I = Escaped.begin(), E = Escaped.end(); I != E; ++I) if (!ETraits->hasTrait(*I, RegionAndSymbolInvalidationTraits::TK_PreserveContents) && !ETraits->hasTrait(*I, RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) RegularEscape.insert(*I); if (RegularEscape.empty()) return State; return ((const CHECKER *)Checker)->checkPointerEscape(State, RegularEscape, Call, Kind); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForPointerEscape( CheckerManager::CheckPointerEscapeFunc(checker, _checkPointerEscape)); } }; class ConstPointerEscape { template static ProgramStateRef _checkConstPointerEscape(void *Checker, ProgramStateRef State, const InvalidatedSymbols &Escaped, const CallEvent *Call, PointerEscapeKind Kind, RegionAndSymbolInvalidationTraits *ETraits) { if (!ETraits) return State; InvalidatedSymbols ConstEscape; for (InvalidatedSymbols::const_iterator I = Escaped.begin(), E = Escaped.end(); I != E; ++I) if (ETraits->hasTrait(*I, RegionAndSymbolInvalidationTraits::TK_PreserveContents) && !ETraits->hasTrait(*I, RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) ConstEscape.insert(*I); if (ConstEscape.empty()) return State; return ((const CHECKER *)Checker)->checkConstPointerEscape(State, ConstEscape, Call, Kind); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForPointerEscape( CheckerManager::CheckPointerEscapeFunc(checker, _checkConstPointerEscape)); } }; template class Event { template static void _checkEvent(void *checker, const void *event) { ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerListenerForEvent( CheckerManager::CheckEventFunc(checker, _checkEvent)); } }; } // end check namespace namespace eval { class Assume { template static ProgramStateRef _evalAssume(void *checker, ProgramStateRef state, const SVal &cond, bool assumption) { return ((const CHECKER *)checker)->evalAssume(state, cond, assumption); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForEvalAssume( CheckerManager::EvalAssumeFunc(checker, _evalAssume)); } }; class Call { template static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) { return ((const CHECKER *)checker)->evalCall(CE, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForEvalCall( CheckerManager::EvalCallFunc(checker, _evalCall)); } }; } // end eval namespace class CheckerBase : public ProgramPointTag { public: StringRef getTagDescription() const; /// See CheckerManager::runCheckersForPrintState. virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const { } }; template class Checker; template <> class Checker : public CheckerBase { virtual void anchor(); public: static void _register(void *checker, CheckerManager &mgr) { } }; template class Checker : public CHECK1, public Checker { public: template static void _register(CHECKER *checker, CheckerManager &mgr) { CHECK1::_register(checker, mgr); Checker::_register(checker, mgr); } }; template class EventDispatcher { CheckerManager *Mgr; public: EventDispatcher() : Mgr(0) { } template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerDispatcherForEvent(); static_cast *>(checker)->Mgr = &mgr; } void dispatchEvent(const EVENT &event) const { Mgr->_dispatchEvent(event); } }; /// \brief We dereferenced a location that may be null. struct ImplicitNullDerefEvent { SVal Location; bool IsLoad; ExplodedNode *SinkNode; BugReporter *BR; }; /// \brief A helper class which wraps a boolean value set to false by default. /// /// This class should behave exactly like 'bool' except that it doesn't need to /// be explicitly initialized. struct DefaultBool { bool val; DefaultBool() : val(false) {} /*implicit*/ operator bool&() { return val; } /*implicit*/ operator const bool&() const { return val; } DefaultBool &operator=(bool b) { val = b; return *this; } }; } // end ento namespace } // end clang namespace #endif