aboutsummaryrefslogtreecommitdiff
path: root/include/clang/EntoSA/PathSensitive/Checker.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/EntoSA/PathSensitive/Checker.h')
-rw-r--r--include/clang/EntoSA/PathSensitive/Checker.h309
1 files changed, 309 insertions, 0 deletions
diff --git a/include/clang/EntoSA/PathSensitive/Checker.h b/include/clang/EntoSA/PathSensitive/Checker.h
new file mode 100644
index 0000000000..a536955c95
--- /dev/null
+++ b/include/clang/EntoSA/PathSensitive/Checker.h
@@ -0,0 +1,309 @@
+//== Checker.h - Abstract interface 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 and CheckerVisitor, classes used for creating
+// domain-specific checks.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_GR_CHECKER
+#define LLVM_CLANG_GR_CHECKER
+
+#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "clang/EntoSA/PathSensitive/ExprEngine.h"
+
+//===----------------------------------------------------------------------===//
+// Checker interface.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+
+namespace ento {
+
+class CheckerContext {
+ ExplodedNodeSet &Dst;
+ StmtNodeBuilder &B;
+ ExprEngine &Eng;
+ ExplodedNode *Pred;
+ SaveAndRestore<bool> OldSink;
+ SaveAndRestore<const void*> OldTag;
+ 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),
+ OldTag(B.Tag, 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);
+ if (N && autoTransition)
+ Dst.Add(N);
+ return N;
+ }
+
+ ExplodedNode *generateNode(const Stmt *stmt, const GRState *state,
+ bool autoTransition = true) {
+ assert(state);
+ ExplodedNode *N = generateNodeImpl(stmt, state, false);
+ 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) {
+ assert(statement && "Only transitions with statements currently supported");
+ ExplodedNode *N = generateNodeImpl(statement, state, false);
+ if (N && autoTransition)
+ addTransition(N);
+ return N;
+ }
+
+ ExplodedNode *generateSink(const Stmt *stmt, const GRState *state = 0) {
+ return generateNodeImpl(stmt, state ? state : getState(), true);
+ }
+
+ ExplodedNode *generateSink(const GRState *state = 0) {
+ assert(statement && "Only transitions with statements currently supported");
+ return generateNodeImpl(statement, state ? state : getState(), true);
+ }
+
+ void addTransition(ExplodedNode *node) {
+ Dst.Add(node);
+ }
+
+ void addTransition(const GRState *state) {
+ 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);
+ else
+ Dst.Add(Pred);
+ }
+
+ // Generate a node with a new program point different from the one that will
+ // be created by the StmtNodeBuilder.
+ void addTransition(const GRState *state, ProgramPoint Loc) {
+ ExplodedNode *N = B.generateNode(Loc, state, Pred);
+ if (N)
+ addTransition(N);
+ }
+
+ 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) {
+ ExplodedNode *node = B.generateNode(stmt, state, Pred);
+ 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);
+ if (markAsSink && node)
+ node->markAsSink();
+ return node;
+ }
+};
+
+class Checker {
+private:
+ friend class ExprEngine;
+
+ // FIXME: Remove the 'tag' option.
+ void GR_Visit(ExplodedNodeSet &Dst,
+ StmtNodeBuilder &Builder,
+ ExprEngine &Eng,
+ const Stmt *S,
+ ExplodedNode *Pred, void *tag, bool isPrevisit,
+ bool& respondsToCallback) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag,
+ isPrevisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind, &respondsToCallback, S);
+ if (isPrevisit)
+ _PreVisit(C, S);
+ else
+ _PostVisit(C, S);
+ }
+
+ bool GR_evalNilReceiver(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
+ ExprEngine &Eng, const ObjCMessageExpr *ME,
+ ExplodedNode *Pred, const GRState *state, void *tag) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
+ 0, ME, state);
+ return evalNilReceiver(C, ME);
+ }
+
+ bool GR_evalCallExpr(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
+ ExprEngine &Eng, const CallExpr *CE,
+ ExplodedNode *Pred, void *tag) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
+ 0, CE);
+ return evalCallExpr(C, CE);
+ }
+
+ // FIXME: Remove the 'tag' option.
+ void GR_VisitBind(ExplodedNodeSet &Dst,
+ StmtNodeBuilder &Builder, ExprEngine &Eng,
+ const Stmt *StoreE, ExplodedNode *Pred, void *tag,
+ SVal location, SVal val,
+ bool isPrevisit) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag,
+ isPrevisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind, 0, StoreE);
+ assert(isPrevisit && "Only previsit supported for now.");
+ PreVisitBind(C, StoreE, location, val);
+ }
+
+ // FIXME: Remove the 'tag' option.
+ void GR_visitLocation(ExplodedNodeSet &Dst,
+ StmtNodeBuilder &Builder,
+ ExprEngine &Eng,
+ const Stmt *S,
+ ExplodedNode *Pred, const GRState *state,
+ SVal location,
+ void *tag, bool isLoad) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag,
+ isLoad ? ProgramPoint::PreLoadKind :
+ ProgramPoint::PreStoreKind, 0, S, state);
+ visitLocation(C, S, location);
+ }
+
+ void GR_evalDeadSymbols(ExplodedNodeSet &Dst, StmtNodeBuilder &Builder,
+ ExprEngine &Eng, const Stmt *S, ExplodedNode *Pred,
+ SymbolReaper &SymReaper, void *tag) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag,
+ ProgramPoint::PostPurgeDeadSymbolsKind, 0, S);
+ evalDeadSymbols(C, SymReaper);
+ }
+
+public:
+ virtual ~Checker();
+ virtual void _PreVisit(CheckerContext &C, const Stmt *S) {}
+ virtual void _PostVisit(CheckerContext &C, const Stmt *S) {}
+ virtual void visitLocation(CheckerContext &C, const Stmt *S, SVal location) {}
+ virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
+ SVal location, SVal val) {}
+ virtual void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper) {}
+ virtual void evalEndPath(EndPathNodeBuilder &B, void *tag,
+ ExprEngine &Eng) {}
+
+ virtual void MarkLiveSymbols(const GRState *state, SymbolReaper &SymReaper) {}
+
+ virtual void VisitBranchCondition(BranchNodeBuilder &Builder,
+ ExprEngine &Eng,
+ const Stmt *Condition, void *tag) {}
+
+ virtual bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME) {
+ return false;
+ }
+
+ virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE) {
+ return false;
+ }
+
+ virtual const GRState *evalAssume(const GRState *state, SVal Cond,
+ bool Assumption, bool *respondsToCallback) {
+ *respondsToCallback = false;
+ return state;
+ }
+
+ virtual bool WantsRegionChangeUpdate(const GRState *state) { return false; }
+
+ virtual const GRState *EvalRegionChanges(const GRState *state,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ bool *respondsToCallback) {
+ *respondsToCallback = false;
+ return state;
+ }
+
+ virtual void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B,
+ ExprEngine &Eng) {}
+};
+
+} // end GR namespace
+
+} // end clang namespace
+
+#endif
+