summaryrefslogtreecommitdiffstats
path: root/include/clang/StaticAnalyzer
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/StaticAnalyzer')
-rw-r--r--include/clang/StaticAnalyzer/Checkers/LocalCheckers.h1
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/BugReporter/BugType.h10
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerManager.h352
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerProvider.h5
-rw-r--r--include/clang/StaticAnalyzer/Core/CheckerV2.h191
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h160
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h187
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h14
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h4
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h16
-rw-r--r--include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h5
-rw-r--r--include/clang/StaticAnalyzer/Frontend/FrontendActions.h2
13 files changed, 760 insertions, 201 deletions
diff --git a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
index 42feb78..afba12d 100644
--- a/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
+++ b/include/clang/StaticAnalyzer/Checkers/LocalCheckers.h
@@ -40,7 +40,6 @@ TransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
const LangOptions& lopts);
void RegisterExperimentalChecks(ExprEngine &Eng);
-void RegisterExperimentalInternalChecks(ExprEngine &Eng);
void RegisterCallInliner(ExprEngine &Eng);
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
index 1786fe6..93d7958 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h
@@ -72,6 +72,7 @@ protected:
friend class BugReportEquivClass;
virtual void Profile(llvm::FoldingSetNodeID& hash) const {
+ hash.AddPointer(&BT);
hash.AddInteger(getLocation().getRawEncoding());
hash.AddString(Description);
}
@@ -277,6 +278,8 @@ private:
void FlushReport(BugReportEquivClass& EQ);
+ llvm::FoldingSet<BugReportEquivClass> EQClasses;
+
protected:
BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
D(d) {}
@@ -302,6 +305,10 @@ public:
iterator begin() { return BugTypes.begin(); }
iterator end() { return BugTypes.end(); }
+ typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
+ EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
+ EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
+
ASTContext& getContext() { return D.getASTContext(); }
SourceManager& getSourceManager() { return D.getSourceManager(); }
@@ -344,6 +351,13 @@ public:
}
static bool classof(const BugReporter* R) { return true; }
+
+private:
+ llvm::StringMap<BugType *> StrBugTypes;
+
+ /// \brief Returns a BugType that is associated with the given name and
+ /// category.
+ BugType *getBugTypeForName(llvm::StringRef name, llvm::StringRef category);
};
// FIXME: Get rid of GRBugReporter. It's the wrong abstraction.
diff --git a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
index 2793284..7b9bb03 100644
--- a/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
+++ b/include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
@@ -29,8 +29,6 @@ class BugType {
private:
const std::string Name;
const std::string Category;
- llvm::FoldingSet<BugReportEquivClass> EQClasses;
- friend class BugReporter;
bool SuppressonSink;
public:
BugType(llvm::StringRef name, llvm::StringRef cat)
@@ -48,14 +46,6 @@ public:
void setSuppressOnSink(bool x) { SuppressonSink = x; }
virtual void FlushReports(BugReporter& BR);
-
- typedef llvm::FoldingSet<BugReportEquivClass>::iterator iterator;
- iterator begin() { return EQClasses.begin(); }
- iterator end() { return EQClasses.end(); }
-
- typedef llvm::FoldingSet<BugReportEquivClass>::const_iterator const_iterator;
- const_iterator begin() const { return EQClasses.begin(); }
- const_iterator end() const { return EQClasses.end(); }
};
class BuiltinBug : public BugType {
diff --git a/include/clang/StaticAnalyzer/Core/CheckerManager.h b/include/clang/StaticAnalyzer/Core/CheckerManager.h
index 65c8b80..2768195 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
diff --git a/include/clang/StaticAnalyzer/Core/CheckerProvider.h b/include/clang/StaticAnalyzer/Core/CheckerProvider.h
index 414ad92..40b838e 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerProvider.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerProvider.h
@@ -17,6 +17,10 @@
#include "llvm/ADT/StringRef.h"
#include <vector>
+namespace llvm {
+ class raw_ostream;
+}
+
namespace clang {
namespace ento {
@@ -45,6 +49,7 @@ public:
virtual ~CheckerProvider();
virtual void registerCheckers(CheckerManager &checkerMgr,
CheckerOptInfo *checkOpts, unsigned numCheckOpts) = 0;
+ virtual void printHelp(llvm::raw_ostream &OS) = 0;
};
} // end ento namespace
diff --git a/include/clang/StaticAnalyzer/Core/CheckerV2.h b/include/clang/StaticAnalyzer/Core/CheckerV2.h
index 8c96866..e080d19 100644
--- a/include/clang/StaticAnalyzer/Core/CheckerV2.h
+++ b/include/clang/StaticAnalyzer/Core/CheckerV2.h
@@ -41,7 +41,9 @@ class ASTDecl {
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
- mgr._registerForDecl(checker, _checkDecl<CHECKER>, _handlesDecl);
+ mgr._registerForDecl(CheckerManager::CheckDeclFunc(checker,
+ _checkDecl<CHECKER>),
+ _handlesDecl);
}
};
@@ -55,12 +57,197 @@ class ASTCodeBody {
public:
template <typename CHECKER>
static void _register(CHECKER *checker, CheckerManager &mgr) {
- mgr._registerForBody(checker, _checkBody<CHECKER>);
+ mgr._registerForBody(CheckerManager::CheckDeclFunc(checker,
+ _checkBody<CHECKER>));
+ }
+};
+
+template <typename STMT>
+class PreStmt {
+ template <typename CHECKER>
+ static void _checkStmt(void *checker, const Stmt *S, CheckerContext &C) {
+ ((const CHECKER *)checker)->checkPreStmt(llvm::cast<STMT>(S), C);
+ }
+
+ static bool _handlesStmt(const Stmt *S) {
+ return llvm::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(llvm::cast<STMT>(S), C);
+ }
+
+ static bool _handlesStmt(const Stmt *S) {
+ return llvm::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 ObjCMessage &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 PostObjCMessage {
+ template <typename CHECKER>
+ static void _checkObjCMessage(void *checker, const ObjCMessage &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 Location {
+ template <typename CHECKER>
+ static void _checkLocation(void *checker, const SVal &location, bool isLoad,
+ CheckerContext &C) {
+ ((const CHECKER *)checker)->checkLocation(location, isLoad, C);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForLocation(
+ CheckerManager::CheckLocationFunc(checker, _checkLocation<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 EndPath {
+ template <typename CHECKER>
+ static void _checkEndPath(void *checker, EndOfFunctionNodeBuilder &B,
+ ExprEngine &Eng) {
+ ((const CHECKER *)checker)->checkEndPath(B, Eng);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForEndPath(
+ CheckerManager::CheckEndPathFunc(checker, _checkEndPath<CHECKER>));
+ }
+};
+
+class LiveSymbols {
+ template <typename CHECKER>
+ static void _checkLiveSymbols(void *checker, const GRState *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 const GRState *_checkRegionChanges(void *checker, const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End) {
+ return ((const CHECKER *)checker)->checkRegionChanges(state, Begin, End);
+ }
+ template <typename CHECKER>
+ static bool _wantsRegionChangeUpdate(void *checker, const GRState *state) {
+ return ((const CHECKER *)checker)->wantsRegionChangeUpdate(state);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForRegionChanges(
+ CheckerManager::CheckRegionChangesFunc(checker,
+ _checkRegionChanges<CHECKER>),
+ CheckerManager::WantsRegionChangeUpdateFunc(checker,
+ _wantsRegionChangeUpdate<CHECKER>));
}
};
} // end check namespace
+namespace eval {
+
+class Call {
+ template <typename CHECKER>
+ static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) {
+ return ((const CHECKER *)checker)->evalCall(CE, C);
+ }
+
+public:
+ template <typename CHECKER>
+ static void _register(CHECKER *checker, CheckerManager &mgr) {
+ mgr._registerForEvalCall(
+ CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>));
+ }
+};
+
+} // end eval namespace
+
template <typename CHECK1, typename CHECK2=check::_VoidCheck,
typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck,
typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck,
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h
index 22c2027..627bc0a 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Checker.h
@@ -15,8 +15,7 @@
#ifndef LLVM_CLANG_GR_CHECKER
#define LLVM_CLANG_GR_CHECKER
-#include "clang/Analysis/Support/SaveAndRestore.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
//===----------------------------------------------------------------------===//
// Checker interface.
@@ -26,163 +25,6 @@ namespace clang {
namespace ento {
-class CheckerContext {
- ExplodedNodeSet &Dst;
- StmtNodeBuilder &B;
- ExprEngine &Eng;
- ExplodedNode *Pred;
- SaveAndRestore<bool> OldSink;
- const void *checkerTag;
- SaveAndRestore<ProgramPoint::Kind> OldPointKind;
- SaveOr OldHasGen;
- const GRState *ST;
- const Stmt *statement;
- const unsigned size;
-public:
- bool *respondsToCallback;
-public:
- CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder,
- ExprEngine &eng, ExplodedNode *pred,
- const void *tag, ProgramPoint::Kind K,
- bool *respondsToCB = 0,
- const Stmt *stmt = 0, const GRState *st = 0)
- : Dst(dst), B(builder), Eng(eng), Pred(pred),
- OldSink(B.BuildSinks),
- checkerTag(tag),
- OldPointKind(B.PointKind, K),
- OldHasGen(B.hasGeneratedNode),
- ST(st), statement(stmt), size(Dst.size()),
- respondsToCallback(respondsToCB) {}
-
- ~CheckerContext();
-
- ExprEngine &getEngine() {
- return Eng;
- }
-
- AnalysisManager &getAnalysisManager() {
- return Eng.getAnalysisManager();
- }
-
- ConstraintManager &getConstraintManager() {
- return Eng.getConstraintManager();
- }
-
- StoreManager &getStoreManager() {
- return Eng.getStoreManager();
- }
-
- ExplodedNodeSet &getNodeSet() { return Dst; }
- StmtNodeBuilder &getNodeBuilder() { return B; }
- ExplodedNode *&getPredecessor() { return Pred; }
- const GRState *getState() { return ST ? ST : B.GetState(Pred); }
-
- ASTContext &getASTContext() {
- return Eng.getContext();
- }
-
- BugReporter &getBugReporter() {
- return Eng.getBugReporter();
- }
-
- SourceManager &getSourceManager() {
- return getBugReporter().getSourceManager();
- }
-
- SValBuilder &getSValBuilder() {
- return Eng.getSValBuilder();
- }
-
- ExplodedNode *generateNode(bool autoTransition = true) {
- assert(statement && "Only transitions with statements currently supported");
- ExplodedNode *N = generateNodeImpl(statement, getState(), false,
- checkerTag);
- if (N && autoTransition)
- Dst.Add(N);
- return N;
- }
-
- ExplodedNode *generateNode(const Stmt *stmt, const GRState *state,
- bool autoTransition = true, const void *tag = 0) {
- assert(state);
- ExplodedNode *N = generateNodeImpl(stmt, state, false,
- tag ? tag : checkerTag);
- if (N && autoTransition)
- addTransition(N);
- return N;
- }
-
- ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
- bool autoTransition = true) {
- assert(statement && "Only transitions with statements currently supported");
- ExplodedNode *N = generateNodeImpl(statement, state, pred, false);
- if (N && autoTransition)
- addTransition(N);
- return N;
- }
-
- ExplodedNode *generateNode(const GRState *state, bool autoTransition = true,
- const void *tag = 0) {
- assert(statement && "Only transitions with statements currently supported");
- ExplodedNode *N = generateNodeImpl(statement, state, false,
- tag ? tag : checkerTag);
- if (N && autoTransition)
- addTransition(N);
- return N;
- }
-
- ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) {
- return generateNodeImpl(stmt, state ? state : getState(), true,
- checkerTag);
- }
-
- ExplodedNode *generateSink(const GRState *state = 0) {
- assert(statement && "Only transitions with statements currently supported");
- return generateNodeImpl(statement, state ? state : getState(), true,
- checkerTag);
- }
-
- void addTransition(ExplodedNode *node) {
- Dst.Add(node);
- }
-
- void addTransition(const GRState *state, const void *tag = 0) {
- assert(state);
- // If the 'state' is not new, we need to check if the cached state 'ST'
- // is new.
- if (state != getState() || (ST && ST != B.GetState(Pred)))
- // state is new or equals to ST.
- generateNode(state, true, tag);
- else
- Dst.Add(Pred);
- }
-
- void EmitReport(BugReport *R) {
- Eng.getBugReporter().EmitReport(R);
- }
-
- AnalysisContext *getCurrentAnalysisContext() const {
- return Pred->getLocationContext()->getAnalysisContext();
- }
-
-private:
- ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
- bool markAsSink, const void *tag) {
- ExplodedNode *node = B.generateNode(stmt, state, Pred, tag);
- if (markAsSink && node)
- node->markAsSink();
- return node;
- }
-
- ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
- ExplodedNode *pred, bool markAsSink) {
- ExplodedNode *node = B.generateNode(stmt, state, pred, checkerTag);
- if (markAsSink && node)
- node->markAsSink();
- return node;
- }
-};
-
class Checker {
private:
friend class ExprEngine;
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
new file mode 100644
index 0000000..4429c6b
--- /dev/null
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h
@@ -0,0 +1,187 @@
+//== CheckerContext.h - Context info for path-sensitive 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 CheckerContext that provides contextual info for
+// path-sensitive checkers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
+#define LLVM_CLANG_SA_CORE_PATHSENSITIVE_CHECKERCONTEXT
+
+#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
+
+namespace clang {
+
+namespace ento {
+
+class CheckerContext {
+ ExplodedNodeSet &Dst;
+ StmtNodeBuilder &B;
+ ExprEngine &Eng;
+ ExplodedNode *Pred;
+ SaveAndRestore<bool> OldSink;
+ const void *checkerTag;
+ SaveAndRestore<ProgramPoint::Kind> OldPointKind;
+ SaveOr OldHasGen;
+ const GRState *ST;
+ const Stmt *statement;
+ const unsigned size;
+public:
+ bool *respondsToCallback;
+public:
+ CheckerContext(ExplodedNodeSet &dst, StmtNodeBuilder &builder,
+ ExprEngine &eng, ExplodedNode *pred,
+ const void *tag, ProgramPoint::Kind K,
+ bool *respondsToCB = 0,
+ const Stmt *stmt = 0, const GRState *st = 0)
+ : Dst(dst), B(builder), Eng(eng), Pred(pred),
+ OldSink(B.BuildSinks),
+ checkerTag(tag),
+ OldPointKind(B.PointKind, K),
+ OldHasGen(B.hasGeneratedNode),
+ ST(st), statement(stmt), size(Dst.size()),
+ respondsToCallback(respondsToCB) {}
+
+ ~CheckerContext();
+
+ ExprEngine &getEngine() {
+ return Eng;
+ }
+
+ AnalysisManager &getAnalysisManager() {
+ return Eng.getAnalysisManager();
+ }
+
+ ConstraintManager &getConstraintManager() {
+ return Eng.getConstraintManager();
+ }
+
+ StoreManager &getStoreManager() {
+ return Eng.getStoreManager();
+ }
+
+ ExplodedNodeSet &getNodeSet() { return Dst; }
+ StmtNodeBuilder &getNodeBuilder() { return B; }
+ ExplodedNode *&getPredecessor() { return Pred; }
+ const GRState *getState() { return ST ? ST : B.GetState(Pred); }
+ const Stmt *getStmt() const { return statement; }
+
+ ASTContext &getASTContext() {
+ return Eng.getContext();
+ }
+
+ BugReporter &getBugReporter() {
+ return Eng.getBugReporter();
+ }
+
+ SourceManager &getSourceManager() {
+ return getBugReporter().getSourceManager();
+ }
+
+ SValBuilder &getSValBuilder() {
+ return Eng.getSValBuilder();
+ }
+
+ ExplodedNode *generateNode(bool autoTransition = true) {
+ assert(statement && "Only transitions with statements currently supported");
+ ExplodedNode *N = generateNodeImpl(statement, getState(), false,
+ checkerTag);
+ if (N && autoTransition)
+ Dst.Add(N);
+ return N;
+ }
+
+ ExplodedNode *generateNode(const Stmt *stmt, const GRState *state,
+ bool autoTransition = true, const void *tag = 0) {
+ assert(state);
+ ExplodedNode *N = generateNodeImpl(stmt, state, false,
+ tag ? tag : checkerTag);
+ if (N && autoTransition)
+ addTransition(N);
+ return N;
+ }
+
+ ExplodedNode *generateNode(const GRState *state, ExplodedNode *pred,
+ bool autoTransition = true) {
+ assert(statement && "Only transitions with statements currently supported");
+ ExplodedNode *N = generateNodeImpl(statement, state, pred, false);
+ if (N && autoTransition)
+ addTransition(N);
+ return N;
+ }
+
+ ExplodedNode *generateNode(const GRState *state, bool autoTransition = true,
+ const void *tag = 0) {
+ assert(statement && "Only transitions with statements currently supported");
+ ExplodedNode *N = generateNodeImpl(statement, state, false,
+ tag ? tag : checkerTag);
+ if (N && autoTransition)
+ addTransition(N);
+ return N;
+ }
+
+ ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) {
+ return generateNodeImpl(stmt, state ? state : getState(), true,
+ checkerTag);
+ }
+
+ ExplodedNode *generateSink(const GRState *state = 0) {
+ assert(statement && "Only transitions with statements currently supported");
+ return generateNodeImpl(statement, state ? state : getState(), true,
+ checkerTag);
+ }
+
+ void addTransition(ExplodedNode *node) {
+ Dst.Add(node);
+ }
+
+ void addTransition(const GRState *state, const void *tag = 0) {
+ assert(state);
+ // If the 'state' is not new, we need to check if the cached state 'ST'
+ // is new.
+ if (state != getState() || (ST && ST != B.GetState(Pred)))
+ // state is new or equals to ST.
+ generateNode(state, true, tag);
+ else
+ Dst.Add(Pred);
+ }
+
+ void EmitReport(BugReport *R) {
+ Eng.getBugReporter().EmitReport(R);
+ }
+
+ AnalysisContext *getCurrentAnalysisContext() const {
+ return Pred->getLocationContext()->getAnalysisContext();
+ }
+
+private:
+ ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
+ bool markAsSink, const void *tag) {
+ ExplodedNode *node = B.generateNode(stmt, state, Pred, tag);
+ if (markAsSink && node)
+ node->markAsSink();
+ return node;
+ }
+
+ ExplodedNode *generateNodeImpl(const Stmt* stmt, const GRState *state,
+ ExplodedNode *pred, bool markAsSink) {
+ ExplodedNode *node = B.generateNode(stmt, state, pred, checkerTag);
+ if (markAsSink && node)
+ node->markAsSink();
+ return node;
+ }
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
index 800e63a..25c6447 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
@@ -447,16 +447,22 @@ class EndOfFunctionNodeBuilder {
CoreEngine &Eng;
const CFGBlock& B;
ExplodedNode* Pred;
+ void *Tag;
public:
bool hasGeneratedNode;
public:
- EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e)
- : Eng(*e), B(*b), Pred(N), hasGeneratedNode(false) {}
+ EndOfFunctionNodeBuilder(const CFGBlock* b, ExplodedNode* N, CoreEngine* e,
+ void *checkerTag = 0)
+ : Eng(*e), B(*b), Pred(N), Tag(checkerTag), hasGeneratedNode(false) {}
~EndOfFunctionNodeBuilder();
+ EndOfFunctionNodeBuilder withCheckerTag(void *tag) {
+ return EndOfFunctionNodeBuilder(&B, Pred, &Eng, tag);
+ }
+
WorkList &getWorkList() { return *Eng.WList; }
ExplodedNode* getPredecessor() const { return Pred; }
@@ -471,8 +477,8 @@ public:
B.getBlockID());
}
- ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
- ExplodedNode *P = 0);
+ ExplodedNode* generateNode(const GRState* State, ExplodedNode *P = 0,
+ const void *tag = 0);
void GenerateCallExitNode(const GRState *state);
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
index 767644a..16f54ee 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -137,6 +137,10 @@ public:
virtual AnalysisManager &getAnalysisManager() { return AMgr; }
+ CheckerManager &getCheckerManager() const {
+ return *AMgr.getCheckerManager();
+ }
+
SValBuilder &getSValBuilder() { return svalBuilder; }
TransferFuncs& getTF() { return *TF; }
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h b/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h
index 411441f..07cdbf5 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h
@@ -151,7 +151,21 @@ namespace ento {
typedef bool data_type;
static inline data_type MakeData(void* const* p) {
- return (bool) (uintptr_t) p;
+ return p ? (data_type) (uintptr_t) *p
+ : data_type();
+ }
+ static inline void *MakeVoidPtr(data_type d) {
+ return (void*) (uintptr_t) d;
+ }
+ };
+
+ // Partial specialization for unsigned.
+ template <> struct GRStatePartialTrait<unsigned> {
+ typedef unsigned data_type;
+
+ static inline data_type MakeData(void* const* p) {
+ return p ? (data_type) (uintptr_t) *p
+ : data_type();
}
static inline void *MakeVoidPtr(data_type d) {
return (void*) (uintptr_t) d;
diff --git a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
index 4c3e379..9d6298f 100644
--- a/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
+++ b/include/clang/StaticAnalyzer/Frontend/CheckerRegistration.h
@@ -12,12 +12,15 @@
namespace clang {
class AnalyzerOptions;
+ class LangOptions;
class Diagnostic;
namespace ento {
class CheckerManager;
-CheckerManager *registerCheckers(const AnalyzerOptions &opts,Diagnostic &diags);
+CheckerManager *registerCheckers(const AnalyzerOptions &opts,
+ const LangOptions &langOpts,
+ Diagnostic &diags);
} // end ento namespace
diff --git a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
index e3867a2..f014181 100644
--- a/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
+++ b/include/clang/StaticAnalyzer/Frontend/FrontendActions.h
@@ -26,6 +26,8 @@ protected:
llvm::StringRef InFile);
};
+void printCheckerHelp(llvm::raw_ostream &OS);
+
} // end GR namespace
} // end namespace clang
OpenPOWER on IntegriCloud