| //== 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 <typename DECL> |
| class ASTDecl { |
| template <typename CHECKER> |
| static void _checkDecl(void *checker, const Decl *D, AnalysisManager& mgr, |
| BugReporter &BR) { |
| ((const CHECKER *)checker)->checkASTDecl(cast<DECL>(D), mgr, BR); |
| } |
| |
| static bool _handlesDecl(const Decl *D) { |
| return isa<DECL>(D); |
| } |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForDecl(CheckerManager::CheckDeclFunc(checker, |
| _checkDecl<CHECKER>), |
| _handlesDecl); |
| } |
| }; |
| |
| class ASTCodeBody { |
| template <typename CHECKER> |
| static void _checkBody(void *checker, const Decl *D, AnalysisManager& mgr, |
| BugReporter &BR) { |
| ((const CHECKER *)checker)->checkASTCodeBody(D, mgr, BR); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForBody(CheckerManager::CheckDeclFunc(checker, |
| _checkBody<CHECKER>)); |
| } |
| }; |
| |
| class EndOfTranslationUnit { |
| template <typename CHECKER> |
| static void _checkEndOfTranslationUnit(void *checker, |
| const TranslationUnitDecl *TU, |
| AnalysisManager& mgr, |
| BugReporter &BR) { |
| ((const CHECKER *)checker)->checkEndOfTranslationUnit(TU, mgr, BR); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr){ |
| mgr._registerForEndOfTranslationUnit( |
| CheckerManager::CheckEndOfTranslationUnit(checker, |
| _checkEndOfTranslationUnit<CHECKER>)); |
| } |
| }; |
| |
| template <typename STMT> |
| class PreStmt { |
| template <typename CHECKER> |
| static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { |
| ((const CHECKER *)checker)->checkPreStmt(cast<STMT>(S), C); |
| } |
| |
| static bool _handlesStmt(const Stmt *S) { |
| return isa<STMT>(S); |
| } |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForPreStmt(CheckerManager::CheckStmtFunc(checker, |
| _checkStmt<CHECKER>), |
| _handlesStmt); |
| } |
| }; |
| |
| template <typename STMT> |
| class PostStmt { |
| template <typename CHECKER> |
| static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) { |
| ((const CHECKER *)checker)->checkPostStmt(cast<STMT>(S), C); |
| } |
| |
| static bool _handlesStmt(const Stmt *S) { |
| return isa<STMT>(S); |
| } |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForPostStmt(CheckerManager::CheckStmtFunc(checker, |
| _checkStmt<CHECKER>), |
| _handlesStmt); |
| } |
| }; |
| |
| class PreObjCMessage { |
| template <typename CHECKER> |
| static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, |
| CheckerContext &C) { |
| ((const CHECKER *)checker)->checkPreObjCMessage(msg, C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForPreObjCMessage( |
| CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); |
| } |
| }; |
| |
| class ObjCMessageNil { |
| template <typename CHECKER> |
| static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, |
| CheckerContext &C) { |
| ((const CHECKER *)checker)->checkObjCMessageNil(msg, C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForObjCMessageNil( |
| CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); |
| } |
| }; |
| |
| class PostObjCMessage { |
| template <typename CHECKER> |
| static void _checkObjCMessage(void *checker, const ObjCMethodCall &msg, |
| CheckerContext &C) { |
| ((const CHECKER *)checker)->checkPostObjCMessage(msg, C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForPostObjCMessage( |
| CheckerManager::CheckObjCMessageFunc(checker, _checkObjCMessage<CHECKER>)); |
| } |
| }; |
| |
| 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, |
| const SVal &location, bool isLoad, const Stmt *S, |
| CheckerContext &C) { |
| ((const CHECKER *)checker)->checkLocation(location, isLoad, S, C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForLocation( |
| CheckerManager::CheckLocationFunc(checker, _checkLocation<CHECKER>)); |
| } |
| }; |
| |
| class Bind { |
| template <typename CHECKER> |
| 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 <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForBind( |
| CheckerManager::CheckBindFunc(checker, _checkBind<CHECKER>)); |
| } |
| }; |
| |
| class EndAnalysis { |
| template <typename CHECKER> |
| static void _checkEndAnalysis(void *checker, ExplodedGraph &G, |
| BugReporter &BR, ExprEngine &Eng) { |
| ((const CHECKER *)checker)->checkEndAnalysis(G, BR, Eng); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForEndAnalysis( |
| CheckerManager::CheckEndAnalysisFunc(checker, _checkEndAnalysis<CHECKER>)); |
| } |
| }; |
| |
| class BeginFunction { |
| template <typename CHECKER> |
| static void _checkBeginFunction(void *checker, CheckerContext &C) { |
| ((const CHECKER *)checker)->checkBeginFunction(C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForBeginFunction(CheckerManager::CheckBeginFunctionFunc( |
| checker, _checkBeginFunction<CHECKER>)); |
| } |
| }; |
| |
| class EndFunction { |
| template <typename CHECKER> |
| static void _checkEndFunction(void *checker, const ReturnStmt *RS, |
| CheckerContext &C) { |
| ((const CHECKER *)checker)->checkEndFunction(RS, C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForEndFunction( |
| CheckerManager::CheckEndFunctionFunc(checker, _checkEndFunction<CHECKER>)); |
| } |
| }; |
| |
| class BranchCondition { |
| template <typename CHECKER> |
| static void _checkBranchCondition(void *checker, const Stmt *Condition, |
| CheckerContext & C) { |
| ((const CHECKER *)checker)->checkBranchCondition(Condition, C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForBranchCondition( |
| CheckerManager::CheckBranchConditionFunc(checker, |
| _checkBranchCondition<CHECKER>)); |
| } |
| }; |
| |
| class NewAllocator { |
| template <typename CHECKER> |
| static void _checkNewAllocator(void *checker, const CXXNewExpr *NE, |
| SVal Target, CheckerContext &C) { |
| ((const CHECKER *)checker)->checkNewAllocator(NE, Target, C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForNewAllocator( |
| CheckerManager::CheckNewAllocatorFunc(checker, |
| _checkNewAllocator<CHECKER>)); |
| } |
| }; |
| |
| class LiveSymbols { |
| template <typename CHECKER> |
| static void _checkLiveSymbols(void *checker, ProgramStateRef state, |
| SymbolReaper &SR) { |
| ((const CHECKER *)checker)->checkLiveSymbols(state, SR); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForLiveSymbols( |
| CheckerManager::CheckLiveSymbolsFunc(checker, _checkLiveSymbols<CHECKER>)); |
| } |
| }; |
| |
| class DeadSymbols { |
| template <typename CHECKER> |
| static void _checkDeadSymbols(void *checker, |
| SymbolReaper &SR, CheckerContext &C) { |
| ((const CHECKER *)checker)->checkDeadSymbols(SR, C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForDeadSymbols( |
| CheckerManager::CheckDeadSymbolsFunc(checker, _checkDeadSymbols<CHECKER>)); |
| } |
| }; |
| |
| class RegionChanges { |
| template <typename CHECKER> |
| static ProgramStateRef |
| _checkRegionChanges(void *checker, |
| ProgramStateRef state, |
| const InvalidatedSymbols *invalidated, |
| ArrayRef<const MemRegion *> Explicits, |
| ArrayRef<const MemRegion *> Regions, |
| const LocationContext *LCtx, |
| const CallEvent *Call) { |
| return ((const CHECKER *) checker)->checkRegionChanges(state, invalidated, |
| Explicits, Regions, |
| LCtx, Call); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForRegionChanges( |
| CheckerManager::CheckRegionChangesFunc(checker, |
| _checkRegionChanges<CHECKER>)); |
| } |
| }; |
| |
| class PointerEscape { |
| template <typename CHECKER> |
| 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 <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForPointerEscape( |
| CheckerManager::CheckPointerEscapeFunc(checker, |
| _checkPointerEscape<CHECKER>)); |
| } |
| }; |
| |
| class ConstPointerEscape { |
| template <typename CHECKER> |
| 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 <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForPointerEscape( |
| CheckerManager::CheckPointerEscapeFunc(checker, |
| _checkConstPointerEscape<CHECKER>)); |
| } |
| }; |
| |
| |
| template <typename EVENT> |
| class Event { |
| template <typename CHECKER> |
| static void _checkEvent(void *checker, const void *event) { |
| ((const CHECKER *)checker)->checkEvent(*(const EVENT *)event); |
| } |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerListenerForEvent<EVENT>( |
| CheckerManager::CheckEventFunc(checker, _checkEvent<CHECKER>)); |
| } |
| }; |
| |
| } // end check namespace |
| |
| namespace eval { |
| |
| class Assume { |
| template <typename CHECKER> |
| static ProgramStateRef _evalAssume(void *checker, |
| ProgramStateRef state, |
| const SVal &cond, |
| bool assumption) { |
| return ((const CHECKER *)checker)->evalAssume(state, cond, assumption); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForEvalAssume( |
| CheckerManager::EvalAssumeFunc(checker, _evalAssume<CHECKER>)); |
| } |
| }; |
| |
| class Call { |
| template <typename CHECKER> |
| static bool _evalCall(void *checker, const CallEvent &Call, |
| CheckerContext &C) { |
| return ((const CHECKER *)checker)->evalCall(Call, C); |
| } |
| |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerForEvalCall( |
| CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>)); |
| } |
| }; |
| |
| } // end eval namespace |
| |
| class CheckerBase : public ProgramPointTag { |
| CheckName Name; |
| friend class ::clang::ento::CheckerManager; |
| |
| public: |
| StringRef getTagDescription() const override; |
| CheckName getCheckName() 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 <typename CHECK1, typename... CHECKs> |
| class Checker : public CHECK1, public CHECKs..., public CheckerBase { |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| CHECK1::_register(checker, mgr); |
| Checker<CHECKs...>::_register(checker, mgr); |
| } |
| }; |
| |
| template <typename CHECK1> |
| class Checker<CHECK1> : public CHECK1, public CheckerBase { |
| public: |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| CHECK1::_register(checker, mgr); |
| } |
| }; |
| |
| template <typename EVENT> |
| class EventDispatcher { |
| CheckerManager *Mgr; |
| public: |
| EventDispatcher() : Mgr(nullptr) { } |
| |
| template <typename CHECKER> |
| static void _register(CHECKER *checker, CheckerManager &mgr) { |
| mgr._registerDispatcherForEvent<EVENT>(); |
| static_cast<EventDispatcher<EVENT> *>(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; |
| }; |
| |
| /// 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 |