summaryrefslogtreecommitdiff
path: root/include/clang/StaticAnalyzer/Core/CheckerManager.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/StaticAnalyzer/Core/CheckerManager.h')
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h352
1 files changed, 329 insertions, 23 deletions
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 65c8b80aa2a8a..276819549d1a8 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerManager.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerManager.h
@@ -14,23 +14,92 @@
#ifndef LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
#define LLVM_CLANG_SA_CORE_CHECKERMANAGER_H
+#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/FoldingSet.h"
#include <vector>
namespace clang {
class Decl;
+ class Stmt;
+ class CallExpr;
namespace ento {
class ExprEngine;
class AnalysisManager;
class BugReporter;
+ class CheckerContext;
+ class ObjCMessage;
+ class SVal;
+ class ExplodedNode;
+ class ExplodedNodeSet;
+ class ExplodedGraph;
+ class GRState;
+ class EndOfFunctionNodeBuilder;
+ class MemRegion;
+ class SymbolReaper;
+
+class GraphExpander {
+public:
+ virtual ~GraphExpander();
+ virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) = 0;
+};
+
+struct VoidCheckerFnParm {};
+template <typename P1=VoidCheckerFnParm, typename P2=VoidCheckerFnParm,
+ typename P3=VoidCheckerFnParm, typename P4=VoidCheckerFnParm>
+class CheckerFn {
+ typedef void (*Func)(void *, P1, P2, P3, P4);
+ Func Fn;
+public:
+ void *Checker;
+ CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ void operator()(P1 p1, P2 p2, P3 p3, P4 p4) { Fn(Checker, p1, p2, p3, p4); }
+};
+
+template <typename P1, typename P2, typename P3>
+class CheckerFn<P1, P2, P3, VoidCheckerFnParm> {
+ typedef void (*Func)(void *, P1, P2, P3);
+ Func Fn;
+public:
+ void *Checker;
+ CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ void operator()(P1 p1, P2 p2, P3 p3) { Fn(Checker, p1, p2, p3); }
+};
+
+template <typename P1, typename P2>
+class CheckerFn<P1, P2, VoidCheckerFnParm, VoidCheckerFnParm> {
+ typedef void (*Func)(void *, P1, P2);
+ Func Fn;
+public:
+ void *Checker;
+ CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ void operator()(P1 p1, P2 p2) { Fn(Checker, p1, p2); }
+};
+
+template <>
+class CheckerFn<VoidCheckerFnParm, VoidCheckerFnParm, VoidCheckerFnParm,
+ VoidCheckerFnParm> {
+ typedef void (*Func)(void *);
+ Func Fn;
+public:
+ void *Checker;
+ CheckerFn(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ void operator()() { Fn(Checker); }
+};
class CheckerManager {
+ const LangOptions LangOpts;
+
public:
+ CheckerManager(const LangOptions &langOpts) : LangOpts(langOpts) { }
~CheckerManager();
+ const LangOptions &getLangOptions() const { return LangOpts; }
+
typedef void *CheckerRef;
+ typedef CheckerFn<> CheckerDtor;
//===----------------------------------------------------------------------===//
// registerChecker
@@ -40,17 +109,12 @@ public:
template <typename CHECKER>
void registerChecker() {
CHECKER *checker = new CHECKER();
- Checkers.push_back(std::pair<CheckerRef, Dtor>(checker, destruct<CHECKER>));
+ CheckerDtors.push_back(CheckerDtor(checker, destruct<CHECKER>));
CHECKER::_register(checker, *this);
}
- typedef void (*RegisterToEngFunc)(ExprEngine &Eng);
- void addCheckerRegisterFunction(RegisterToEngFunc fn) {
- Funcs.push_back(fn);
- }
-
//===----------------------------------------------------------------------===//
-// Functions for running checkers.
+// Functions for running checkers for AST traversing..
//===----------------------------------------------------------------------===//
/// \brief Run checkers handling Decls.
@@ -62,48 +126,290 @@ public:
BugReporter &BR);
//===----------------------------------------------------------------------===//
-// Internal registration functions.
+// Functions for running checkers for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+ /// \brief Run checkers for pre-visiting Stmts.
+ 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.
+ void runCheckersForPostStmt(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ const Stmt *S,
+ ExprEngine &Eng) {
+ runCheckersForStmt(/*isPreVisit=*/false, Dst, Src, S, Eng);
+ }
+
+ /// \brief Run checkers for visiting Stmts.
+ void runCheckersForStmt(bool isPreVisit,
+ ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
+ const Stmt *S, ExprEngine &Eng);
+
+ /// \brief Run checkers for pre-visiting obj-c messages.
+ void runCheckersForPreObjCMessage(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ const ObjCMessage &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 ObjCMessage &msg,
+ ExprEngine &Eng) {
+ runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng);
+ }
+
+ /// \brief Run checkers for visiting obj-c messages.
+ void runCheckersForObjCMessage(bool isPreVisit,
+ ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ const ObjCMessage &msg, ExprEngine &Eng);
+
+ /// \brief Run checkers for load/store of a location.
+ void runCheckersForLocation(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ SVal location, bool isLoad,
+ const Stmt *S,
+ ExprEngine &Eng);
+
+ /// \brief Run checkers for end of analysis.
+ void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
+ ExprEngine &Eng);
+
+ /// \brief Run checkers for end of path.
+ void runCheckersForEndPath(EndOfFunctionNodeBuilder &B, ExprEngine &Eng);
+
+ /// \brief Run checkers for live symbols.
+ void runCheckersForLiveSymbols(const GRState *state,
+ SymbolReaper &SymReaper);
+
+ /// \brief Run checkers for dead symbols.
+ void runCheckersForDeadSymbols(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ SymbolReaper &SymReaper, const Stmt *S,
+ ExprEngine &Eng);
+
+ /// \brief True if at least one checker wants to check region changes.
+ bool wantsRegionChangeUpdate(const GRState *state);
+
+ /// \brief Run checkers for region changes.
+ const GRState *runCheckersForRegionChanges(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End);
+
+ /// \brief Run checkers for evaluating a call.
+ void runCheckersForEvalCall(ExplodedNodeSet &Dst,
+ const ExplodedNodeSet &Src,
+ const CallExpr *CE, ExprEngine &Eng,
+ GraphExpander *defaultEval = 0);
+
+//===----------------------------------------------------------------------===//
+// Internal registration functions for AST traversing.
//===----------------------------------------------------------------------===//
// Functions used by the registration mechanism, checkers should not touch
// these directly.
- typedef void (*CheckDeclFunc)(CheckerRef checker, const Decl *D,
- AnalysisManager& mgr, BugReporter &BR);
+ typedef CheckerFn<const Decl *, AnalysisManager&, BugReporter &>
+ CheckDeclFunc;
+ typedef CheckerFn<const Stmt *, CheckerContext &> CheckStmtFunc;
+
typedef bool (*HandlesDeclFunc)(const Decl *D);
- void _registerForDecl(CheckerRef checker, CheckDeclFunc checkfn,
- HandlesDeclFunc isForDeclFn);
+ void _registerForDecl(CheckDeclFunc checkfn, HandlesDeclFunc isForDeclFn);
- void _registerForBody(CheckerRef checker, CheckDeclFunc checkfn);
-
- void registerCheckersToEngine(ExprEngine &eng);
+ void _registerForBody(CheckDeclFunc checkfn);
+
+//===----------------------------------------------------------------------===//
+// Internal registration functions for path-sensitive checking.
+//===----------------------------------------------------------------------===//
+
+ typedef CheckerFn<const ObjCMessage &, CheckerContext &> CheckObjCMessageFunc;
+ typedef CheckerFn<const SVal &/*location*/, bool/*isLoad*/, CheckerContext &>
+ CheckLocationFunc;
+ typedef CheckerFn<ExplodedGraph &, BugReporter &, ExprEngine &>
+ CheckEndAnalysisFunc;
+ typedef CheckerFn<EndOfFunctionNodeBuilder &, ExprEngine &> CheckEndPathFunc;
+ typedef CheckerFn<SymbolReaper &, CheckerContext &> CheckDeadSymbolsFunc;
+ typedef CheckerFn<const GRState *, SymbolReaper &> CheckLiveSymbolsFunc;
+
+ 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 _registerForLocation(CheckLocationFunc checkfn);
+
+ void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
+
+ void _registerForEndPath(CheckEndPathFunc checkfn);
+
+ void _registerForLiveSymbols(CheckLiveSymbolsFunc checkfn);
+
+ void _registerForDeadSymbols(CheckDeadSymbolsFunc checkfn);
+
+ class CheckRegionChangesFunc {
+ typedef const GRState * (*Func)(void *, const GRState *,
+ const MemRegion * const *,
+ const MemRegion * const *);
+ Func Fn;
+ public:
+ void *Checker;
+ CheckRegionChangesFunc(void *checker, Func fn) : Fn(fn), Checker(checker) {}
+ const GRState *operator()(const GRState *state,
+ const MemRegion * const *begin,
+ const MemRegion * const *end) {
+ return Fn(Checker, state, begin, end);
+ }
+ };
+
+ class WantsRegionChangeUpdateFunc {
+ typedef bool (*Func)(void *, const GRState *);
+ Func Fn;
+ public:
+ void *Checker;
+ WantsRegionChangeUpdateFunc(void *checker, Func fn)
+ : Fn(fn), Checker(checker) { }
+ bool operator()(const GRState *state) {
+ return Fn(Checker, state);
+ }
+ };
+
+ void _registerForRegionChanges(CheckRegionChangesFunc checkfn,
+ WantsRegionChangeUpdateFunc wantUpdateFn);
+
+ class EvalCallFunc {
+ typedef bool (*Func)(void *, const CallExpr *, CheckerContext &);
+ Func Fn;
+ public:
+ void *Checker;
+ EvalCallFunc(void *checker, Func fn) : Fn(fn), Checker(checker) { }
+ bool operator()(const CallExpr *CE, CheckerContext &C) {
+ return Fn(Checker, CE, C);
+ }
+ };
+
+ void _registerForEvalCall(EvalCallFunc checkfn);
+
+//===----------------------------------------------------------------------===//
+// Implementation details.
+//===----------------------------------------------------------------------===//
private:
template <typename CHECKER>
static void destruct(void *obj) { delete static_cast<CHECKER *>(obj); }
- std::vector<RegisterToEngFunc> Funcs;
+ std::vector<CheckerDtor> CheckerDtors;
struct DeclCheckerInfo {
- CheckerRef Checker;
CheckDeclFunc CheckFn;
HandlesDeclFunc IsForDeclFn;
};
std::vector<DeclCheckerInfo> DeclCheckers;
- std::vector<std::pair<CheckerRef, CheckDeclFunc> > BodyCheckers;
-
- typedef void (*Dtor)(void *);
- std::vector<std::pair<CheckerRef, Dtor> > Checkers;
+ std::vector<CheckDeclFunc> BodyCheckers;
- typedef llvm::SmallVector<std::pair<CheckerRef, CheckDeclFunc>, 4>
- CachedDeclCheckers;
+ typedef llvm::SmallVector<CheckDeclFunc, 4> CachedDeclCheckers;
typedef llvm::DenseMap<unsigned, CachedDeclCheckers> CachedDeclCheckersMapTy;
CachedDeclCheckersMapTy CachedDeclCheckersMap;
+
+ struct StmtCheckerInfo {
+ CheckStmtFunc CheckFn;
+ HandlesStmtFunc IsForStmtFn;
+ bool IsPreVisit;
+ };
+ std::vector<StmtCheckerInfo> StmtCheckers;
+
+ struct CachedStmtCheckersKey {
+ unsigned StmtKind;
+ bool IsPreVisit;
+
+ CachedStmtCheckersKey() : StmtKind(0), IsPreVisit(0) { }
+ CachedStmtCheckersKey(unsigned stmtKind, bool isPreVisit)
+ : StmtKind(stmtKind), IsPreVisit(isPreVisit) { }
+
+ static CachedStmtCheckersKey getSentinel() {
+ return CachedStmtCheckersKey(~0U, 0);
+ }
+ unsigned getHashValue() const {
+ llvm::FoldingSetNodeID ID;
+ ID.AddInteger(StmtKind);
+ ID.AddBoolean(IsPreVisit);
+ return ID.ComputeHash();
+ }
+ bool operator==(const CachedStmtCheckersKey &RHS) const {
+ return StmtKind == RHS.StmtKind && IsPreVisit == RHS.IsPreVisit;
+ }
+ };
+ friend struct llvm::DenseMapInfo<CachedStmtCheckersKey>;
+
+ typedef llvm::SmallVector<CheckStmtFunc, 4> CachedStmtCheckers;
+ typedef llvm::DenseMap<CachedStmtCheckersKey, CachedStmtCheckers>
+ CachedStmtCheckersMapTy;
+ CachedStmtCheckersMapTy CachedStmtCheckersMap;
+
+ CachedStmtCheckers *getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit);
+
+ std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers;
+ std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers;
+
+ std::vector<CheckLocationFunc> LocationCheckers;
+
+ std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;
+
+ std::vector<CheckEndPathFunc> EndPathCheckers;
+
+ std::vector<CheckLiveSymbolsFunc> LiveSymbolsCheckers;
+
+ std::vector<CheckDeadSymbolsFunc> DeadSymbolsCheckers;
+
+ struct RegionChangesCheckerInfo {
+ CheckRegionChangesFunc CheckFn;
+ WantsRegionChangeUpdateFunc WantUpdateFn;
+ };
+ std::vector<RegionChangesCheckerInfo> RegionChangesCheckers;
+
+ std::vector<EvalCallFunc> EvalCallCheckers;
};
} // end ento namespace
} // end clang namespace
+namespace llvm {
+ /// Define DenseMapInfo so that CachedStmtCheckersKey can be used as key
+ /// in DenseMap and DenseSets.
+ template <>
+ struct DenseMapInfo<clang::ento::CheckerManager::CachedStmtCheckersKey> {
+ static inline clang::ento::CheckerManager::CachedStmtCheckersKey
+ getEmptyKey() {
+ return clang::ento::CheckerManager::CachedStmtCheckersKey();
+ }
+ static inline clang::ento::CheckerManager::CachedStmtCheckersKey
+ getTombstoneKey() {
+ return clang::ento::CheckerManager::CachedStmtCheckersKey::getSentinel();
+ }
+
+ static unsigned
+ getHashValue(clang::ento::CheckerManager::CachedStmtCheckersKey S) {
+ return S.getHashValue();
+ }
+
+ static bool isEqual(clang::ento::CheckerManager::CachedStmtCheckersKey LHS,
+ clang::ento::CheckerManager::CachedStmtCheckersKey RHS) {
+ return LHS == RHS;
+ }
+ };
+} // end namespace llvm
+
#endif