//== Checker.h - Registration mechanism for checkers -------------*- C++ -*--=// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines Checker, used to create and register checkers. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H #define LLVM_CLANG_STATICANALYZER_CORE_CHECKER_H #include "clang/Analysis/ProgramPoint.h" #include "clang/Basic/LangOptions.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 { 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 ObjCMessageNil { template static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, CheckerContext &C) { ((const CHECKER *)checker)->checkObjCMessageNil(msg, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForObjCMessageNil( 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, 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, SVal location, 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 BeginFunction { template static void _checkBeginFunction(void *checker, CheckerContext &C) { ((const CHECKER *)checker)->checkBeginFunction(C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForBeginFunction(CheckerManager::CheckBeginFunctionFunc( checker, _checkBeginFunction)); } }; class EndFunction { template static void _checkEndFunction(void *checker, const ReturnStmt *RS, CheckerContext &C) { ((const CHECKER *)checker)->checkEndFunction(RS, 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 NewAllocator { template static void _checkNewAllocator(void *checker, const CXXAllocatorCall &Call, CheckerContext &C) { ((const CHECKER *)checker)->checkNewAllocator(Call, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForNewAllocator( CheckerManager::CheckNewAllocatorFunc(checker, _checkNewAllocator)); } }; 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 LocationContext *LCtx, const CallEvent *Call) { return ((const CHECKER *) checker)->checkRegionChanges(state, invalidated, Explicits, Regions, LCtx, Call); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForRegionChanges( CheckerManager::CheckRegionChangesFunc(checker, _checkRegionChanges)); } }; 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 (SymbolRef Sym : Escaped) if (!ETraits->hasTrait( Sym, RegionAndSymbolInvalidationTraits::TK_PreserveContents) && !ETraits->hasTrait( Sym, RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) RegularEscape.insert(Sym); 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 (SymbolRef Sym : Escaped) { if (ETraits->hasTrait( Sym, RegionAndSymbolInvalidationTraits::TK_PreserveContents) && !ETraits->hasTrait( Sym, RegionAndSymbolInvalidationTraits::TK_SuppressEscape)) ConstEscape.insert(Sym); } 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, 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 CallEvent &Call, CheckerContext &C) { return ((const CHECKER *)checker)->evalCall(Call, C); } public: template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerForEvalCall( CheckerManager::EvalCallFunc(checker, _evalCall)); } }; } // end eval namespace class CheckerBase : public ProgramPointTag { CheckerNameRef Name; friend class ::clang::ento::CheckerManager; public: StringRef getTagDescription() const override; CheckerNameRef getCheckerName() const; /// See CheckerManager::runCheckersForPrintState. virtual void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const { } }; /// Dump checker name to stream. raw_ostream& operator<<(raw_ostream &Out, const CheckerBase &Checker); /// Tag that can use a checker name as a message provider /// (see SimpleProgramPointTag). class CheckerProgramPointTag : public SimpleProgramPointTag { public: CheckerProgramPointTag(StringRef CheckerName, StringRef Msg); CheckerProgramPointTag(const CheckerBase *Checker, StringRef Msg); }; template class Checker : public CHECK1, public CHECKs..., public CheckerBase { public: template static void _register(CHECKER *checker, CheckerManager &mgr) { CHECK1::_register(checker, mgr); Checker::_register(checker, mgr); } }; template class Checker : public CHECK1, public CheckerBase { public: template static void _register(CHECKER *checker, CheckerManager &mgr) { CHECK1::_register(checker, mgr); } }; template class EventDispatcher { CheckerManager *Mgr = nullptr; public: EventDispatcher() = default; template static void _register(CHECKER *checker, CheckerManager &mgr) { mgr._registerDispatcherForEvent(); static_cast *>(checker)->Mgr = &mgr; } void dispatchEvent(const EVENT &event) const { Mgr->_dispatchEvent(event); } }; /// We dereferenced a location that may be null. struct ImplicitNullDerefEvent { SVal Location; bool IsLoad; ExplodedNode *SinkNode; BugReporter *BR; // When true, the dereference is in the source code directly. When false, the // dereference might happen later (for example pointer passed to a parameter // that is marked with nonnull attribute.) bool IsDirectDereference; static int Tag; }; } // end ento namespace } // end clang namespace #endif