summaryrefslogtreecommitdiffstats
path: root/include/clang/Checker/PathSensitive
diff options
context:
space:
mode:
Diffstat (limited to 'include/clang/Checker/PathSensitive')
-rw-r--r--include/clang/Checker/PathSensitive/AnalysisManager.h149
-rw-r--r--include/clang/Checker/PathSensitive/BasicValueFactory.h198
-rw-r--r--include/clang/Checker/PathSensitive/Checker.h281
-rw-r--r--include/clang/Checker/PathSensitive/CheckerVisitor.def37
-rw-r--r--include/clang/Checker/PathSensitive/CheckerVisitor.h102
-rw-r--r--include/clang/Checker/PathSensitive/ConstraintManager.h75
-rw-r--r--include/clang/Checker/PathSensitive/Environment.h103
-rw-r--r--include/clang/Checker/PathSensitive/ExplodedGraph.h432
-rw-r--r--include/clang/Checker/PathSensitive/GRAuditor.h35
-rw-r--r--include/clang/Checker/PathSensitive/GRBlockCounter.h50
-rw-r--r--include/clang/Checker/PathSensitive/GRCoreEngine.h443
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngine.h422
-rw-r--r--include/clang/Checker/PathSensitive/GRExprEngineBuilders.h76
-rw-r--r--include/clang/Checker/PathSensitive/GRSimpleAPICheck.h40
-rw-r--r--include/clang/Checker/PathSensitive/GRState.h756
-rw-r--r--include/clang/Checker/PathSensitive/GRStateTrait.h148
-rw-r--r--include/clang/Checker/PathSensitive/GRSubEngine.h75
-rw-r--r--include/clang/Checker/PathSensitive/GRTransferFuncs.h85
-rw-r--r--include/clang/Checker/PathSensitive/GRWorkList.h79
-rw-r--r--include/clang/Checker/PathSensitive/MemRegion.h974
-rw-r--r--include/clang/Checker/PathSensitive/SVals.h499
-rw-r--r--include/clang/Checker/PathSensitive/SValuator.h66
-rw-r--r--include/clang/Checker/PathSensitive/Store.h230
-rw-r--r--include/clang/Checker/PathSensitive/SummaryManager.h57
-rw-r--r--include/clang/Checker/PathSensitive/SymbolManager.h385
-rw-r--r--include/clang/Checker/PathSensitive/ValueManager.h208
26 files changed, 6005 insertions, 0 deletions
diff --git a/include/clang/Checker/PathSensitive/AnalysisManager.h b/include/clang/Checker/PathSensitive/AnalysisManager.h
new file mode 100644
index 0000000..fdf52a7
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/AnalysisManager.h
@@ -0,0 +1,149 @@
+//== AnalysisManager.h - Path sensitive analysis data manager ------*- 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 the AnalysisManager class that manages the data and policy
+// for path sensitive analysis.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H
+#define LLVM_CLANG_ANALYSIS_ANALYSISMANAGER_H
+
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/Checker/BugReporter/PathDiagnostic.h"
+
+namespace clang {
+
+class AnalysisManager : public BugReporterData {
+ AnalysisContextManager AnaCtxMgr;
+ LocationContextManager LocCtxMgr;
+
+ ASTContext &Ctx;
+ Diagnostic &Diags;
+ const LangOptions &LangInfo;
+
+ llvm::OwningPtr<PathDiagnosticClient> PD;
+
+ // Configurable components creators.
+ StoreManagerCreator CreateStoreMgr;
+ ConstraintManagerCreator CreateConstraintMgr;
+
+ enum AnalysisScope { ScopeTU, ScopeDecl } AScope;
+
+ bool VisualizeEGDot;
+ bool VisualizeEGUbi;
+ bool PurgeDead;
+
+ /// EargerlyAssume - A flag indicating how the engine should handle
+ // expressions such as: 'x = (y != 0)'. When this flag is true then
+ // the subexpression 'y != 0' will be eagerly assumed to be true or false,
+ // thus evaluating it to the integers 0 or 1 respectively. The upside
+ // is that this can increase analysis precision until we have a better way
+ // to lazily evaluate such logic. The downside is that it eagerly
+ // bifurcates paths.
+ bool EagerlyAssume;
+ bool TrimGraph;
+
+public:
+ AnalysisManager(ASTContext &ctx, Diagnostic &diags,
+ const LangOptions &lang, PathDiagnosticClient *pd,
+ StoreManagerCreator storemgr,
+ ConstraintManagerCreator constraintmgr,
+ bool vizdot, bool vizubi, bool purge, bool eager, bool trim)
+
+ : Ctx(ctx), Diags(diags), LangInfo(lang), PD(pd),
+ CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr),
+ AScope(ScopeDecl),
+ VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge),
+ EagerlyAssume(eager), TrimGraph(trim) {}
+
+ ~AnalysisManager() { FlushDiagnostics(); }
+
+ void ClearContexts() {
+ LocCtxMgr.clear();
+ AnaCtxMgr.clear();
+ }
+
+ StoreManagerCreator getStoreManagerCreator() {
+ return CreateStoreMgr;
+ }
+
+ ConstraintManagerCreator getConstraintManagerCreator() {
+ return CreateConstraintMgr;
+ }
+
+ virtual ASTContext &getASTContext() {
+ return Ctx;
+ }
+
+ virtual SourceManager &getSourceManager() {
+ return getASTContext().getSourceManager();
+ }
+
+ virtual Diagnostic &getDiagnostic() {
+ return Diags;
+ }
+
+ const LangOptions &getLangOptions() const {
+ return LangInfo;
+ }
+
+ virtual PathDiagnosticClient *getPathDiagnosticClient() {
+ return PD.get();
+ }
+
+ void FlushDiagnostics() {
+ if (PD.get())
+ PD->FlushDiagnostics();
+ }
+
+ bool shouldVisualizeGraphviz() const { return VisualizeEGDot; }
+
+ bool shouldVisualizeUbigraph() const { return VisualizeEGUbi; }
+
+ bool shouldVisualize() const {
+ return VisualizeEGDot || VisualizeEGUbi;
+ }
+
+ bool shouldTrimGraph() const { return TrimGraph; }
+
+ bool shouldPurgeDead() const { return PurgeDead; }
+
+ bool shouldEagerlyAssume() const { return EagerlyAssume; }
+
+ CFG *getCFG(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getCFG();
+ }
+
+ LiveVariables *getLiveVariables(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getLiveVariables();
+ }
+
+ ParentMap &getParentMap(Decl const *D) {
+ return AnaCtxMgr.getContext(D)->getParentMap();
+ }
+
+ // Get the top level stack frame.
+ const StackFrameContext *getStackFrame(Decl const *D) {
+ return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), 0, 0, 0, 0);
+ }
+
+ // Get a stack frame with parent.
+ StackFrameContext const *getStackFrame(Decl const *D,
+ LocationContext const *Parent,
+ Stmt const *S, const CFGBlock *Blk,
+ unsigned Idx) {
+ return LocCtxMgr.getStackFrame(AnaCtxMgr.getContext(D), Parent, S, Blk,Idx);
+ }
+};
+
+}
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/BasicValueFactory.h b/include/clang/Checker/PathSensitive/BasicValueFactory.h
new file mode 100644
index 0000000..2f0b6c2
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/BasicValueFactory.h
@@ -0,0 +1,198 @@
+//=== BasicValueFactory.h - Basic values for Path Sens analysis --*- 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 BasicValueFactory, a class that manages the lifetime
+// of APSInt objects and symbolic constraints used by GRExprEngine
+// and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
+#define LLVM_CLANG_ANALYSIS_BASICVALUEFACTORY_H
+
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/SVals.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/ImmutableList.h"
+
+namespace clang {
+
+ class GRState;
+
+class CompoundValData : public llvm::FoldingSetNode {
+ QualType T;
+ llvm::ImmutableList<SVal> L;
+
+public:
+ CompoundValData(QualType t, llvm::ImmutableList<SVal> l)
+ : T(t), L(l) {}
+
+ typedef llvm::ImmutableList<SVal>::iterator iterator;
+ iterator begin() const { return L.begin(); }
+ iterator end() const { return L.end(); }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, QualType T,
+ llvm::ImmutableList<SVal> L);
+
+ void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, T, L); }
+};
+
+class LazyCompoundValData : public llvm::FoldingSetNode {
+ const void *store;
+ const TypedRegion *region;
+public:
+ LazyCompoundValData(const void *st, const TypedRegion *r)
+ : store(st), region(r) {}
+
+ const void *getStore() const { return store; }
+ const TypedRegion *getRegion() const { return region; }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const void *store,
+ const TypedRegion *region);
+
+ void Profile(llvm::FoldingSetNodeID& ID) { Profile(ID, store, region); }
+};
+
+class BasicValueFactory {
+ typedef llvm::FoldingSet<llvm::FoldingSetNodeWrapper<llvm::APSInt> >
+ APSIntSetTy;
+
+ ASTContext& Ctx;
+ llvm::BumpPtrAllocator& BPAlloc;
+
+ APSIntSetTy APSIntSet;
+ void* PersistentSVals;
+ void* PersistentSValPairs;
+
+ llvm::ImmutableList<SVal>::Factory SValListFactory;
+ llvm::FoldingSet<CompoundValData> CompoundValDataSet;
+ llvm::FoldingSet<LazyCompoundValData> LazyCompoundValDataSet;
+
+public:
+ BasicValueFactory(ASTContext& ctx, llvm::BumpPtrAllocator& Alloc)
+ : Ctx(ctx), BPAlloc(Alloc), PersistentSVals(0), PersistentSValPairs(0),
+ SValListFactory(Alloc) {}
+
+ ~BasicValueFactory();
+
+ ASTContext& getContext() const { return Ctx; }
+
+ const llvm::APSInt& getValue(const llvm::APSInt& X);
+ const llvm::APSInt& getValue(const llvm::APInt& X, bool isUnsigned);
+ const llvm::APSInt& getValue(uint64_t X, unsigned BitWidth, bool isUnsigned);
+ const llvm::APSInt& getValue(uint64_t X, QualType T);
+
+ /// Convert - Create a new persistent APSInt with the same value as 'From'
+ /// but with the bitwidth and signedness of 'To'.
+ const llvm::APSInt &Convert(const llvm::APSInt& To,
+ const llvm::APSInt& From) {
+
+ if (To.isUnsigned() == From.isUnsigned() &&
+ To.getBitWidth() == From.getBitWidth())
+ return From;
+
+ return getValue(From.getSExtValue(), To.getBitWidth(), To.isUnsigned());
+ }
+
+ const llvm::APSInt &Convert(QualType T, const llvm::APSInt &From) {
+ assert(T->isIntegerType() || Loc::IsLocType(T));
+ unsigned bitwidth = Ctx.getTypeSize(T);
+ bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
+
+ if (isUnsigned == From.isUnsigned() && bitwidth == From.getBitWidth())
+ return From;
+
+ return getValue(From.getSExtValue(), bitwidth, isUnsigned);
+ }
+
+ const llvm::APSInt& getIntValue(uint64_t X, bool isUnsigned) {
+ QualType T = isUnsigned ? Ctx.UnsignedIntTy : Ctx.IntTy;
+ return getValue(X, T);
+ }
+
+ inline const llvm::APSInt& getMaxValue(const llvm::APSInt &v) {
+ return getValue(llvm::APSInt::getMaxValue(v.getBitWidth(), v.isUnsigned()));
+ }
+
+ inline const llvm::APSInt& getMinValue(const llvm::APSInt &v) {
+ return getValue(llvm::APSInt::getMinValue(v.getBitWidth(), v.isUnsigned()));
+ }
+
+ inline const llvm::APSInt& getMaxValue(QualType T) {
+ assert(T->isIntegerType() || Loc::IsLocType(T));
+ bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
+ return getValue(llvm::APSInt::getMaxValue(Ctx.getTypeSize(T), isUnsigned));
+ }
+
+ inline const llvm::APSInt& getMinValue(QualType T) {
+ assert(T->isIntegerType() || Loc::IsLocType(T));
+ bool isUnsigned = T->isUnsignedIntegerType() || Loc::IsLocType(T);
+ return getValue(llvm::APSInt::getMinValue(Ctx.getTypeSize(T), isUnsigned));
+ }
+
+ inline const llvm::APSInt& Add1(const llvm::APSInt& V) {
+ llvm::APSInt X = V;
+ ++X;
+ return getValue(X);
+ }
+
+ inline const llvm::APSInt& Sub1(const llvm::APSInt& V) {
+ llvm::APSInt X = V;
+ --X;
+ return getValue(X);
+ }
+
+ inline const llvm::APSInt& getZeroWithPtrWidth(bool isUnsigned = true) {
+ return getValue(0, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
+ }
+
+ inline const llvm::APSInt &getIntWithPtrWidth(uint64_t X, bool isUnsigned) {
+ return getValue(X, Ctx.getTypeSize(Ctx.VoidPtrTy), isUnsigned);
+ }
+
+ inline const llvm::APSInt& getTruthValue(bool b, QualType T) {
+ return getValue(b ? 1 : 0, Ctx.getTypeSize(T), false);
+ }
+
+ inline const llvm::APSInt& getTruthValue(bool b) {
+ return getTruthValue(b, Ctx.IntTy);
+ }
+
+ const CompoundValData *getCompoundValData(QualType T,
+ llvm::ImmutableList<SVal> Vals);
+
+ const LazyCompoundValData *getLazyCompoundValData(const void *store,
+ const TypedRegion *region);
+
+ llvm::ImmutableList<SVal> getEmptySValList() {
+ return SValListFactory.GetEmptyList();
+ }
+
+ llvm::ImmutableList<SVal> consVals(SVal X, llvm::ImmutableList<SVal> L) {
+ return SValListFactory.Add(X, L);
+ }
+
+ const llvm::APSInt* EvaluateAPSInt(BinaryOperator::Opcode Op,
+ const llvm::APSInt& V1,
+ const llvm::APSInt& V2);
+
+ const std::pair<SVal, uintptr_t>&
+ getPersistentSValWithData(const SVal& V, uintptr_t Data);
+
+ const std::pair<SVal, SVal>&
+ getPersistentSValPair(const SVal& V1, const SVal& V2);
+
+ const SVal* getPersistentSVal(SVal X);
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/Checker.h b/include/clang/Checker/PathSensitive/Checker.h
new file mode 100644
index 0000000..d498044
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/Checker.h
@@ -0,0 +1,281 @@
+//== 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_ANALYSIS_CHECKER
+#define LLVM_CLANG_ANALYSIS_CHECKER
+#include "clang/Analysis/Support/SaveAndRestore.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
+
+//===----------------------------------------------------------------------===//
+// Checker interface.
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+ class GRExprEngine;
+
+class CheckerContext {
+ ExplodedNodeSet &Dst;
+ GRStmtNodeBuilder &B;
+ GRExprEngine &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;
+ bool DoneEvaluating; // FIXME: This is not a permanent API change.
+public:
+ CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder,
+ GRExprEngine &eng, ExplodedNode *pred,
+ const void *tag, ProgramPoint::Kind K,
+ 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()) {}
+
+ ~CheckerContext();
+
+ GRExprEngine &getEngine() {
+ return Eng;
+ }
+
+ AnalysisManager &getAnalysisManager() {
+ return Eng.getAnalysisManager();
+ }
+
+ ConstraintManager &getConstraintManager() {
+ return Eng.getConstraintManager();
+ }
+
+ StoreManager &getStoreManager() {
+ return Eng.getStoreManager();
+ }
+
+ ExplodedNodeSet &getNodeSet() { return Dst; }
+ GRStmtNodeBuilder &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();
+ }
+
+ ValueManager &getValueManager() {
+ return Eng.getValueManager();
+ }
+
+ SValuator &getSValuator() {
+ return Eng.getSValuator();
+ }
+
+ 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 (state != getState() || (ST && ST != B.GetState(Pred)))
+ GenerateNode(state, true);
+ else
+ Dst.Add(Pred);
+ }
+
+ void EmitReport(BugReport *R) {
+ Eng.getBugReporter().EmitReport(R);
+ }
+
+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 GRExprEngine;
+
+ // FIXME: Remove the 'tag' option.
+ void GR_Visit(ExplodedNodeSet &Dst,
+ GRStmtNodeBuilder &Builder,
+ GRExprEngine &Eng,
+ const Stmt *S,
+ ExplodedNode *Pred, void *tag, bool isPrevisit) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag,
+ isPrevisit ? ProgramPoint::PreStmtKind :
+ ProgramPoint::PostStmtKind, S);
+ if (isPrevisit)
+ _PreVisit(C, S);
+ else
+ _PostVisit(C, S);
+ }
+
+ bool GR_EvalNilReceiver(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
+ GRExprEngine &Eng, const ObjCMessageExpr *ME,
+ ExplodedNode *Pred, const GRState *state, void *tag) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
+ ME, state);
+ return EvalNilReceiver(C, ME);
+ }
+
+ bool GR_EvalCallExpr(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
+ GRExprEngine &Eng, const CallExpr *CE,
+ ExplodedNode *Pred, void *tag) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag, ProgramPoint::PostStmtKind,
+ CE);
+ return EvalCallExpr(C, CE);
+ }
+
+ // FIXME: Remove the 'tag' option.
+ void GR_VisitBind(ExplodedNodeSet &Dst,
+ GRStmtNodeBuilder &Builder, GRExprEngine &Eng,
+ const Stmt *AssignE,
+ 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, StoreE);
+ assert(isPrevisit && "Only previsit supported for now.");
+ PreVisitBind(C, AssignE, StoreE, location, val);
+ }
+
+ // FIXME: Remove the 'tag' option.
+ void GR_VisitLocation(ExplodedNodeSet &Dst,
+ GRStmtNodeBuilder &Builder,
+ GRExprEngine &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, S, state);
+ VisitLocation(C, S, location);
+ }
+
+ void GR_EvalDeadSymbols(ExplodedNodeSet &Dst, GRStmtNodeBuilder &Builder,
+ GRExprEngine &Eng, const Stmt *S, ExplodedNode *Pred,
+ SymbolReaper &SymReaper, void *tag) {
+ CheckerContext C(Dst, Builder, Eng, Pred, tag,
+ ProgramPoint::PostPurgeDeadSymbolsKind, S);
+ EvalDeadSymbols(C, S, 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 *AssignE,
+ const Stmt *StoreE, SVal location, SVal val) {}
+ virtual void EvalDeadSymbols(CheckerContext &C, const Stmt *S,
+ SymbolReaper &SymReaper) {}
+ virtual void EvalEndPath(GREndPathNodeBuilder &B, void *tag,
+ GRExprEngine &Eng) {}
+
+ virtual void VisitBranchCondition(GRBranchNodeBuilder &Builder,
+ GRExprEngine &Eng,
+ 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) {
+ return state;
+ }
+};
+} // end clang namespace
+
+#endif
+
diff --git a/include/clang/Checker/PathSensitive/CheckerVisitor.def b/include/clang/Checker/PathSensitive/CheckerVisitor.def
new file mode 100644
index 0000000..2edc4a3
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/CheckerVisitor.def
@@ -0,0 +1,37 @@
+//===-- CheckerVisitor.def - Metadata for CheckerVisitor ----------------*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the AST nodes accepted by the CheckerVisitor class.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef PREVISIT
+#define PREVISIT(NODE, FALLBACK)
+#endif
+
+#ifndef POSTVISIT
+#define POSTVISIT(NODE, FALLBACK)
+#endif
+
+PREVISIT(ArraySubscriptExpr, Stmt)
+PREVISIT(BinaryOperator, Stmt)
+PREVISIT(CallExpr, Stmt)
+PREVISIT(CXXOperatorCallExpr, CallExpr)
+PREVISIT(DeclStmt, Stmt)
+PREVISIT(ObjCMessageExpr, Stmt)
+PREVISIT(ReturnStmt, Stmt)
+
+POSTVISIT(BlockExpr, Stmt)
+POSTVISIT(BinaryOperator, Stmt)
+POSTVISIT(CallExpr, Stmt)
+POSTVISIT(CXXOperatorCallExpr, CallExpr)
+POSTVISIT(ObjCMessageExpr, Stmt)
+
+#undef PREVISIT
+#undef POSTVISIT
diff --git a/include/clang/Checker/PathSensitive/CheckerVisitor.h b/include/clang/Checker/PathSensitive/CheckerVisitor.h
new file mode 100644
index 0000000..72f0ae1
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/CheckerVisitor.h
@@ -0,0 +1,102 @@
+//== CheckerVisitor.h - Abstract visitor 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 CheckerVisitor.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CHECKERVISITOR
+#define LLVM_CLANG_ANALYSIS_CHECKERVISITOR
+#include "clang/Checker/PathSensitive/Checker.h"
+
+namespace clang {
+
+//===----------------------------------------------------------------------===//
+// Checker visitor interface. Used by subclasses of Checker to specify their
+// own checker visitor logic.
+//===----------------------------------------------------------------------===//
+
+/// CheckerVisitor - This class implements a simple visitor for Stmt subclasses.
+/// Since Expr derives from Stmt, this also includes support for visiting Exprs.
+template<typename ImplClass>
+class CheckerVisitor : public Checker {
+public:
+ virtual void _PreVisit(CheckerContext &C, const Stmt *S) {
+ PreVisit(C, S);
+ }
+
+ virtual void _PostVisit(CheckerContext &C, const Stmt *S) {
+ PostVisit(C, S);
+ }
+
+ void PreVisit(CheckerContext &C, const Stmt *S) {
+ switch (S->getStmtClass()) {
+ default:
+ assert(false && "Unsupport statement.");
+ return;
+
+ case Stmt::ImplicitCastExprClass:
+ case Stmt::CStyleCastExprClass:
+ static_cast<ImplClass*>(this)->PreVisitCastExpr(C,
+ static_cast<const CastExpr*>(S));
+ break;
+
+ case Stmt::CompoundAssignOperatorClass:
+ static_cast<ImplClass*>(this)->PreVisitBinaryOperator(C,
+ static_cast<const BinaryOperator*>(S));
+ break;
+
+#define PREVISIT(NAME, FALLBACK) \
+case Stmt::NAME ## Class:\
+static_cast<ImplClass*>(this)->PreVisit ## NAME(C,static_cast<const NAME*>(S));\
+break;
+#include "clang/Checker/PathSensitive/CheckerVisitor.def"
+ }
+ }
+
+ void PostVisit(CheckerContext &C, const Stmt *S) {
+ switch (S->getStmtClass()) {
+ default:
+ assert(false && "Unsupport statement.");
+ return;
+ case Stmt::CompoundAssignOperatorClass:
+ static_cast<ImplClass*>(this)->PostVisitBinaryOperator(C,
+ static_cast<const BinaryOperator*>(S));
+ break;
+
+#define POSTVISIT(NAME, FALLBACK) \
+case Stmt::NAME ## Class:\
+static_cast<ImplClass*>(this)->\
+PostVisit ## NAME(C,static_cast<const NAME*>(S));\
+break;
+#include "clang/Checker/PathSensitive/CheckerVisitor.def"
+ }
+ }
+
+ void PreVisitStmt(CheckerContext &C, const Stmt *S) {}
+ void PostVisitStmt(CheckerContext &C, const Stmt *S) {}
+
+ void PreVisitCastExpr(CheckerContext &C, const CastExpr *E) {
+ static_cast<ImplClass*>(this)->PreVisitStmt(C, E);
+ }
+
+#define PREVISIT(NAME, FALLBACK) \
+void PreVisit ## NAME(CheckerContext &C, const NAME* S) {\
+ static_cast<ImplClass*>(this)->PreVisit ## FALLBACK(C, S);\
+}
+#define POSTVISIT(NAME, FALLBACK) \
+void PostVisit ## NAME(CheckerContext &C, const NAME* S) {\
+ static_cast<ImplClass*>(this)->PostVisit ## FALLBACK(C, S);\
+}
+#include "clang/Checker/PathSensitive/CheckerVisitor.def"
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/ConstraintManager.h b/include/clang/Checker/PathSensitive/ConstraintManager.h
new file mode 100644
index 0000000..ce7d1b3
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/ConstraintManager.h
@@ -0,0 +1,75 @@
+//== ConstraintManager.h - Constraints on symbolic values.-------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the interface to manage constraints on symbolic values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H
+#define LLVM_CLANG_ANALYSIS_CONSTRAINT_MANAGER_H
+
+// FIXME: Typedef LiveSymbolsTy/DeadSymbolsTy at a more appropriate place.
+#include "clang/Checker/PathSensitive/Store.h"
+
+namespace llvm {
+class APSInt;
+}
+
+namespace clang {
+
+class GRState;
+class GRStateManager;
+class GRSubEngine;
+class SVal;
+
+class ConstraintManager {
+public:
+ virtual ~ConstraintManager();
+ virtual const GRState *Assume(const GRState *state, DefinedSVal Cond,
+ bool Assumption) = 0;
+
+ virtual const GRState *AssumeInBound(const GRState *state, DefinedSVal Idx,
+ DefinedSVal UpperBound, bool Assumption) = 0;
+
+ std::pair<const GRState*, const GRState*> AssumeDual(const GRState *state,
+ DefinedSVal Cond) {
+ return std::make_pair(Assume(state, Cond, true),
+ Assume(state, Cond, false));
+ }
+
+ virtual const llvm::APSInt* getSymVal(const GRState *state,
+ SymbolRef sym) const = 0;
+
+ virtual bool isEqual(const GRState *state, SymbolRef sym,
+ const llvm::APSInt& V) const = 0;
+
+ virtual const GRState *RemoveDeadBindings(const GRState *state,
+ SymbolReaper& SymReaper) = 0;
+
+ virtual void print(const GRState *state, llvm::raw_ostream& Out,
+ const char* nl, const char *sep) = 0;
+
+ virtual void EndPath(const GRState *state) {}
+
+ /// canReasonAbout - Not all ConstraintManagers can accurately reason about
+ /// all SVal values. This method returns true if the ConstraintManager can
+ /// reasonably handle a given SVal value. This is typically queried by
+ /// GRExprEngine to determine if the value should be replaced with a
+ /// conjured symbolic value in order to recover some precision.
+ virtual bool canReasonAbout(SVal X) const = 0;
+};
+
+ConstraintManager* CreateBasicConstraintManager(GRStateManager& statemgr,
+ GRSubEngine &subengine);
+ConstraintManager* CreateRangeConstraintManager(GRStateManager& statemgr,
+ GRSubEngine &subengine);
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/Environment.h b/include/clang/Checker/PathSensitive/Environment.h
new file mode 100644
index 0000000..0852c31
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/Environment.h
@@ -0,0 +1,103 @@
+//== Environment.h - Map from Stmt* to Locations/Values ---------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the Environment and EnvironmentManager classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_ENVIRONMENT_H
+#define LLVM_CLANG_ANALYSIS_ENVIRONMENT_H
+
+// For using typedefs in StoreManager. Should find a better place for these
+// typedefs.
+#include "clang/Checker/PathSensitive/Store.h"
+
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "clang/Checker/PathSensitive/SVals.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/FoldingSet.h"
+
+namespace clang {
+
+class AnalysisContext;
+class EnvironmentManager;
+class ValueManager;
+class LiveVariables;
+
+
+class Environment {
+private:
+ friend class EnvironmentManager;
+
+ // Type definitions.
+ typedef llvm::ImmutableMap<const Stmt*,SVal> BindingsTy;
+
+ // Data.
+ BindingsTy ExprBindings;
+ AnalysisContext *ACtx;
+
+ Environment(BindingsTy eb, AnalysisContext *aCtx)
+ : ExprBindings(eb), ACtx(aCtx) {}
+
+public:
+ typedef BindingsTy::iterator iterator;
+ iterator begin() const { return ExprBindings.begin(); }
+ iterator end() const { return ExprBindings.end(); }
+
+ SVal LookupExpr(const Stmt* E) const {
+ const SVal* X = ExprBindings.lookup(E);
+ return X ? *X : UnknownVal();
+ }
+
+ SVal GetSVal(const Stmt* Ex, ValueManager& ValMgr) const;
+
+ AnalysisContext &getAnalysisContext() const { return *ACtx; }
+
+ /// Profile - Profile the contents of an Environment object for use
+ /// in a FoldingSet.
+ static void Profile(llvm::FoldingSetNodeID& ID, const Environment* E) {
+ E->ExprBindings.Profile(ID);
+ }
+
+ /// Profile - Used to profile the contents of this object for inclusion
+ /// in a FoldingSet.
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Profile(ID, this);
+ }
+
+ bool operator==(const Environment& RHS) const {
+ return ExprBindings == RHS.ExprBindings;
+ }
+};
+
+class EnvironmentManager {
+private:
+ typedef Environment::BindingsTy::Factory FactoryTy;
+ FactoryTy F;
+
+public:
+ EnvironmentManager(llvm::BumpPtrAllocator& Allocator) : F(Allocator) {}
+ ~EnvironmentManager() {}
+
+ Environment getInitialEnvironment(AnalysisContext *ACtx) {
+ return Environment(F.GetEmptyMap(), ACtx);
+ }
+
+ Environment BindExpr(Environment Env, const Stmt *S, SVal V,
+ bool Invalidate);
+
+ Environment RemoveDeadBindings(Environment Env, const Stmt *S,
+ SymbolReaper &SymReaper, const GRState *ST,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/ExplodedGraph.h b/include/clang/Checker/PathSensitive/ExplodedGraph.h
new file mode 100644
index 0000000..d6c4436
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/ExplodedGraph.h
@@ -0,0 +1,432 @@
+//=-- ExplodedGraph.h - Local, Path-Sens. "Exploded Graph" -*- 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 the template classes ExplodedNode and ExplodedGraph,
+// which represent a path-sensitive, intra-procedural "exploded graph."
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
+#define LLVM_CLANG_ANALYSIS_EXPLODEDGRAPH
+
+#include "clang/Analysis/ProgramPoint.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/AST/Decl.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/GraphTraits.h"
+#include "llvm/ADT/DepthFirstIterator.h"
+#include "llvm/Support/Casting.h"
+#include "clang/Analysis/Support/BumpVector.h"
+
+namespace clang {
+
+class GRState;
+class CFG;
+class ASTContext;
+class ExplodedGraph;
+
+//===----------------------------------------------------------------------===//
+// ExplodedGraph "implementation" classes. These classes are not typed to
+// contain a specific kind of state. Typed-specialized versions are defined
+// on top of these classes.
+//===----------------------------------------------------------------------===//
+
+class ExplodedNode : public llvm::FoldingSetNode {
+ friend class ExplodedGraph;
+ friend class GRCoreEngine;
+ friend class GRStmtNodeBuilder;
+ friend class GRBranchNodeBuilder;
+ friend class GRIndirectGotoNodeBuilder;
+ friend class GRSwitchNodeBuilder;
+ friend class GREndPathNodeBuilder;
+
+ class NodeGroup {
+ enum { Size1 = 0x0, SizeOther = 0x1, AuxFlag = 0x2, Mask = 0x3 };
+ uintptr_t P;
+
+ unsigned getKind() const {
+ return P & 0x1;
+ }
+
+ void* getPtr() const {
+ assert (!getFlag());
+ return reinterpret_cast<void*>(P & ~Mask);
+ }
+
+ ExplodedNode *getNode() const {
+ return reinterpret_cast<ExplodedNode*>(getPtr());
+ }
+
+ public:
+ NodeGroup() : P(0) {}
+
+ ExplodedNode **begin() const;
+
+ ExplodedNode **end() const;
+
+ unsigned size() const;
+
+ bool empty() const { return (P & ~Mask) == 0; }
+
+ void addNode(ExplodedNode* N, ExplodedGraph &G);
+
+ void setFlag() {
+ assert(P == 0);
+ P = AuxFlag;
+ }
+
+ bool getFlag() const {
+ return P & AuxFlag ? true : false;
+ }
+ };
+
+ /// Location - The program location (within a function body) associated
+ /// with this node.
+ const ProgramPoint Location;
+
+ /// State - The state associated with this node.
+ const GRState* State;
+
+ /// Preds - The predecessors of this node.
+ NodeGroup Preds;
+
+ /// Succs - The successors of this node.
+ NodeGroup Succs;
+
+public:
+
+ explicit ExplodedNode(const ProgramPoint& loc, const GRState* state)
+ : Location(loc), State(state) {}
+
+ /// getLocation - Returns the edge associated with the given node.
+ ProgramPoint getLocation() const { return Location; }
+
+ const LocationContext *getLocationContext() const {
+ return getLocation().getLocationContext();
+ }
+
+ const Decl &getCodeDecl() const { return *getLocationContext()->getDecl(); }
+
+ CFG &getCFG() const { return *getLocationContext()->getCFG(); }
+
+ ParentMap &getParentMap() const {return getLocationContext()->getParentMap();}
+
+ LiveVariables &getLiveVariables() const {
+ return *getLocationContext()->getLiveVariables();
+ }
+
+ const GRState* getState() const { return State; }
+
+ template <typename T>
+ const T* getLocationAs() const { return llvm::dyn_cast<T>(&Location); }
+
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ const ProgramPoint& Loc, const GRState* state) {
+ ID.Add(Loc);
+ ID.AddPointer(state);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Profile(ID, getLocation(), getState());
+ }
+
+ /// addPredeccessor - Adds a predecessor to the current node, and
+ /// in tandem add this node as a successor of the other node.
+ void addPredecessor(ExplodedNode* V, ExplodedGraph &G);
+
+ unsigned succ_size() const { return Succs.size(); }
+ unsigned pred_size() const { return Preds.size(); }
+ bool succ_empty() const { return Succs.empty(); }
+ bool pred_empty() const { return Preds.empty(); }
+
+ bool isSink() const { return Succs.getFlag(); }
+ void markAsSink() { Succs.setFlag(); }
+
+ ExplodedNode* getFirstPred() {
+ return pred_empty() ? NULL : *(pred_begin());
+ }
+
+ const ExplodedNode* getFirstPred() const {
+ return const_cast<ExplodedNode*>(this)->getFirstPred();
+ }
+
+ // Iterators over successor and predecessor vertices.
+ typedef ExplodedNode** succ_iterator;
+ typedef const ExplodedNode* const * const_succ_iterator;
+ typedef ExplodedNode** pred_iterator;
+ typedef const ExplodedNode* const * const_pred_iterator;
+
+ pred_iterator pred_begin() { return Preds.begin(); }
+ pred_iterator pred_end() { return Preds.end(); }
+
+ const_pred_iterator pred_begin() const {
+ return const_cast<ExplodedNode*>(this)->pred_begin();
+ }
+ const_pred_iterator pred_end() const {
+ return const_cast<ExplodedNode*>(this)->pred_end();
+ }
+
+ succ_iterator succ_begin() { return Succs.begin(); }
+ succ_iterator succ_end() { return Succs.end(); }
+
+ const_succ_iterator succ_begin() const {
+ return const_cast<ExplodedNode*>(this)->succ_begin();
+ }
+ const_succ_iterator succ_end() const {
+ return const_cast<ExplodedNode*>(this)->succ_end();
+ }
+
+ // For debugging.
+
+public:
+
+ class Auditor {
+ public:
+ virtual ~Auditor();
+ virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst) = 0;
+ };
+
+ static void SetAuditor(Auditor* A);
+};
+
+// FIXME: Is this class necessary?
+class InterExplodedGraphMap {
+ llvm::DenseMap<const ExplodedNode*, ExplodedNode*> M;
+ friend class ExplodedGraph;
+
+public:
+ ExplodedNode* getMappedNode(const ExplodedNode* N) const;
+
+ InterExplodedGraphMap() {}
+ virtual ~InterExplodedGraphMap() {}
+};
+
+class ExplodedGraph {
+protected:
+ friend class GRCoreEngine;
+
+ // Type definitions.
+ typedef llvm::SmallVector<ExplodedNode*,2> RootsTy;
+ typedef llvm::SmallVector<ExplodedNode*,10> EndNodesTy;
+
+ /// Roots - The roots of the simulation graph. Usually there will be only
+ /// one, but clients are free to establish multiple subgraphs within a single
+ /// SimulGraph. Moreover, these subgraphs can often merge when paths from
+ /// different roots reach the same state at the same program location.
+ RootsTy Roots;
+
+ /// EndNodes - The nodes in the simulation graph which have been
+ /// specially marked as the endpoint of an abstract simulation path.
+ EndNodesTy EndNodes;
+
+ /// Nodes - The nodes in the graph.
+ llvm::FoldingSet<ExplodedNode> Nodes;
+
+ /// BVC - Allocator and context for allocating nodes and their predecessor
+ /// and successor groups.
+ BumpVectorContext BVC;
+
+ /// Ctx - The ASTContext used to "interpret" CodeDecl.
+ ASTContext& Ctx;
+
+ /// NumNodes - The number of nodes in the graph.
+ unsigned NumNodes;
+
+public:
+ /// getNode - Retrieve the node associated with a (Location,State) pair,
+ /// where the 'Location' is a ProgramPoint in the CFG. If no node for
+ /// this pair exists, it is created. IsNew is set to true if
+ /// the node was freshly created.
+
+ ExplodedNode* getNode(const ProgramPoint& L, const GRState *State,
+ bool* IsNew = 0);
+
+ ExplodedGraph* MakeEmptyGraph() const {
+ return new ExplodedGraph(Ctx);
+ }
+
+ /// addRoot - Add an untyped node to the set of roots.
+ ExplodedNode* addRoot(ExplodedNode* V) {
+ Roots.push_back(V);
+ return V;
+ }
+
+ /// addEndOfPath - Add an untyped node to the set of EOP nodes.
+ ExplodedNode* addEndOfPath(ExplodedNode* V) {
+ EndNodes.push_back(V);
+ return V;
+ }
+
+ ExplodedGraph(ASTContext& ctx) : Ctx(ctx), NumNodes(0) {}
+
+ ~ExplodedGraph() {}
+
+ unsigned num_roots() const { return Roots.size(); }
+ unsigned num_eops() const { return EndNodes.size(); }
+
+ bool empty() const { return NumNodes == 0; }
+ unsigned size() const { return NumNodes; }
+
+ // Iterators.
+ typedef ExplodedNode NodeTy;
+ typedef llvm::FoldingSet<ExplodedNode> AllNodesTy;
+ typedef NodeTy** roots_iterator;
+ typedef NodeTy* const * const_roots_iterator;
+ typedef NodeTy** eop_iterator;
+ typedef NodeTy* const * const_eop_iterator;
+ typedef AllNodesTy::iterator node_iterator;
+ typedef AllNodesTy::const_iterator const_node_iterator;
+
+ node_iterator nodes_begin() { return Nodes.begin(); }
+
+ node_iterator nodes_end() { return Nodes.end(); }
+
+ const_node_iterator nodes_begin() const { return Nodes.begin(); }
+
+ const_node_iterator nodes_end() const { return Nodes.end(); }
+
+ roots_iterator roots_begin() { return Roots.begin(); }
+
+ roots_iterator roots_end() { return Roots.end(); }
+
+ const_roots_iterator roots_begin() const { return Roots.begin(); }
+
+ const_roots_iterator roots_end() const { return Roots.end(); }
+
+ eop_iterator eop_begin() { return EndNodes.begin(); }
+
+ eop_iterator eop_end() { return EndNodes.end(); }
+
+ const_eop_iterator eop_begin() const { return EndNodes.begin(); }
+
+ const_eop_iterator eop_end() const { return EndNodes.end(); }
+
+ llvm::BumpPtrAllocator & getAllocator() { return BVC.getAllocator(); }
+ BumpVectorContext &getNodeAllocator() { return BVC; }
+
+ ASTContext& getContext() { return Ctx; }
+
+ typedef llvm::DenseMap<const ExplodedNode*, ExplodedNode*> NodeMap;
+
+ std::pair<ExplodedGraph*, InterExplodedGraphMap*>
+ Trim(const NodeTy* const* NBeg, const NodeTy* const* NEnd,
+ llvm::DenseMap<const void*, const void*> *InverseMap = 0) const;
+
+ ExplodedGraph* TrimInternal(const ExplodedNode* const * NBeg,
+ const ExplodedNode* const * NEnd,
+ InterExplodedGraphMap *M,
+ llvm::DenseMap<const void*, const void*> *InverseMap) const;
+};
+
+class ExplodedNodeSet {
+ typedef llvm::SmallPtrSet<ExplodedNode*,5> ImplTy;
+ ImplTy Impl;
+
+public:
+ ExplodedNodeSet(ExplodedNode* N) {
+ assert (N && !static_cast<ExplodedNode*>(N)->isSink());
+ Impl.insert(N);
+ }
+
+ ExplodedNodeSet() {}
+
+ inline void Add(ExplodedNode* N) {
+ if (N && !static_cast<ExplodedNode*>(N)->isSink()) Impl.insert(N);
+ }
+
+ ExplodedNodeSet& operator=(const ExplodedNodeSet &X) {
+ Impl = X.Impl;
+ return *this;
+ }
+
+ typedef ImplTy::iterator iterator;
+ typedef ImplTy::const_iterator const_iterator;
+
+ unsigned size() const { return Impl.size(); }
+ bool empty() const { return Impl.empty(); }
+
+ void clear() { Impl.clear(); }
+ void insert(const ExplodedNodeSet &S) {
+ if (empty())
+ Impl = S.Impl;
+ else
+ Impl.insert(S.begin(), S.end());
+ }
+
+ inline iterator begin() { return Impl.begin(); }
+ inline iterator end() { return Impl.end(); }
+
+ inline const_iterator begin() const { return Impl.begin(); }
+ inline const_iterator end() const { return Impl.end(); }
+};
+
+} // end clang namespace
+
+// GraphTraits
+
+namespace llvm {
+ template<> struct GraphTraits<clang::ExplodedNode*> {
+ typedef clang::ExplodedNode NodeType;
+ typedef NodeType::succ_iterator ChildIteratorType;
+ typedef llvm::df_iterator<NodeType*> nodes_iterator;
+
+ static inline NodeType* getEntryNode(NodeType* N) {
+ return N;
+ }
+
+ static inline ChildIteratorType child_begin(NodeType* N) {
+ return N->succ_begin();
+ }
+
+ static inline ChildIteratorType child_end(NodeType* N) {
+ return N->succ_end();
+ }
+
+ static inline nodes_iterator nodes_begin(NodeType* N) {
+ return df_begin(N);
+ }
+
+ static inline nodes_iterator nodes_end(NodeType* N) {
+ return df_end(N);
+ }
+ };
+
+ template<> struct GraphTraits<const clang::ExplodedNode*> {
+ typedef const clang::ExplodedNode NodeType;
+ typedef NodeType::const_succ_iterator ChildIteratorType;
+ typedef llvm::df_iterator<NodeType*> nodes_iterator;
+
+ static inline NodeType* getEntryNode(NodeType* N) {
+ return N;
+ }
+
+ static inline ChildIteratorType child_begin(NodeType* N) {
+ return N->succ_begin();
+ }
+
+ static inline ChildIteratorType child_end(NodeType* N) {
+ return N->succ_end();
+ }
+
+ static inline nodes_iterator nodes_begin(NodeType* N) {
+ return df_begin(N);
+ }
+
+ static inline nodes_iterator nodes_end(NodeType* N) {
+ return df_end(N);
+ }
+ };
+
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRAuditor.h b/include/clang/Checker/PathSensitive/GRAuditor.h
new file mode 100644
index 0000000..015c82e
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRAuditor.h
@@ -0,0 +1,35 @@
+//==- GRAuditor.h - Observers of the creation of ExplodedNodes------*- 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 GRAuditor and its primary subclasses, an interface
+// to audit the creation of ExplodedNodes. This interface can be used
+// to implement simple checkers that do not mutate analysis state but
+// instead operate by perfoming simple logical checks at key monitoring
+// locations (e.g., function calls).
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRAUDITOR
+#define LLVM_CLANG_ANALYSIS_GRAUDITOR
+
+namespace clang {
+
+class ExplodedNode;
+class GRStateManager;
+
+class GRAuditor {
+public:
+ virtual ~GRAuditor() {}
+ virtual bool Audit(ExplodedNode* N, GRStateManager& M) = 0;
+};
+
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRBlockCounter.h b/include/clang/Checker/PathSensitive/GRBlockCounter.h
new file mode 100644
index 0000000..67ed953
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRBlockCounter.h
@@ -0,0 +1,50 @@
+//==- GRBlockCounter.h - ADT for counting block visits -------------*- 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 GRBlockCounter, an abstract data type used to count
+// the number of times a given block has been visited along a path
+// analyzed by GRCoreEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER
+#define LLVM_CLANG_ANALYSIS_GRBLOCKCOUNTER
+
+namespace llvm {
+ class BumpPtrAllocator;
+}
+
+namespace clang {
+
+class GRBlockCounter {
+ void* Data;
+
+ GRBlockCounter(void* D) : Data(D) {}
+
+public:
+ GRBlockCounter() : Data(0) {}
+
+ unsigned getNumVisited(unsigned BlockID) const;
+
+ class Factory {
+ void* F;
+ public:
+ Factory(llvm::BumpPtrAllocator& Alloc);
+ ~Factory();
+
+ GRBlockCounter GetEmptyCounter();
+ GRBlockCounter IncrementCount(GRBlockCounter BC, unsigned BlockID);
+ };
+
+ friend class Factory;
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRCoreEngine.h b/include/clang/Checker/PathSensitive/GRCoreEngine.h
new file mode 100644
index 0000000..6da4581
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRCoreEngine.h
@@ -0,0 +1,443 @@
+//==- GRCoreEngine.h - Path-Sensitive Dataflow Engine --------------*- 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 a generic engine for intraprocedural, path-sensitive,
+// dataflow analysis via graph reachability.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRENGINE
+#define LLVM_CLANG_ANALYSIS_GRENGINE
+
+#include "clang/AST/Expr.h"
+#include "clang/Checker/PathSensitive/ExplodedGraph.h"
+#include "clang/Checker/PathSensitive/GRWorkList.h"
+#include "clang/Checker/PathSensitive/GRBlockCounter.h"
+#include "clang/Checker/PathSensitive/GRAuditor.h"
+#include "clang/Checker/PathSensitive/GRSubEngine.h"
+#include "llvm/ADT/OwningPtr.h"
+
+namespace clang {
+
+//===----------------------------------------------------------------------===//
+/// GRCoreEngine - Implements the core logic of the graph-reachability
+/// analysis. It traverses the CFG and generates the ExplodedGraph.
+/// Program "states" are treated as opaque void pointers.
+/// The template class GRCoreEngine (which subclasses GRCoreEngine)
+/// provides the matching component to the engine that knows the actual types
+/// for states. Note that this engine only dispatches to transfer functions
+/// at the statement and block-level. The analyses themselves must implement
+/// any transfer function logic and the sub-expression level (if any).
+class GRCoreEngine {
+ friend class GRStmtNodeBuilder;
+ friend class GRBranchNodeBuilder;
+ friend class GRIndirectGotoNodeBuilder;
+ friend class GRSwitchNodeBuilder;
+ friend class GREndPathNodeBuilder;
+
+ GRSubEngine& SubEngine;
+
+ /// G - The simulation graph. Each node is a (location,state) pair.
+ llvm::OwningPtr<ExplodedGraph> G;
+
+ /// WList - A set of queued nodes that need to be processed by the
+ /// worklist algorithm. It is up to the implementation of WList to decide
+ /// the order that nodes are processed.
+ GRWorkList* WList;
+
+ /// BCounterFactory - A factory object for created GRBlockCounter objects.
+ /// These are used to record for key nodes in the ExplodedGraph the
+ /// number of times different CFGBlocks have been visited along a path.
+ GRBlockCounter::Factory BCounterFactory;
+
+ void GenerateNode(const ProgramPoint& Loc, const GRState* State,
+ ExplodedNode* Pred);
+
+ void HandleBlockEdge(const BlockEdge& E, ExplodedNode* Pred);
+ void HandleBlockEntrance(const BlockEntrance& E, ExplodedNode* Pred);
+ void HandleBlockExit(CFGBlock* B, ExplodedNode* Pred);
+ void HandlePostStmt(const PostStmt& S, CFGBlock* B,
+ unsigned StmtIdx, ExplodedNode *Pred);
+
+ void HandleBranch(Stmt* Cond, Stmt* Term, CFGBlock* B,
+ ExplodedNode* Pred);
+
+ /// Get the initial state from the subengine.
+ const GRState* getInitialState(const LocationContext *InitLoc) {
+ return SubEngine.getInitialState(InitLoc);
+ }
+
+ void ProcessEndPath(GREndPathNodeBuilder& Builder);
+
+ void ProcessStmt(CFGElement E, GRStmtNodeBuilder& Builder);
+
+ bool ProcessBlockEntrance(CFGBlock* Blk, const GRState* State,
+ GRBlockCounter BC);
+
+
+ void ProcessBranch(Stmt* Condition, Stmt* Terminator,
+ GRBranchNodeBuilder& Builder);
+
+
+ void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& Builder);
+
+
+ void ProcessSwitch(GRSwitchNodeBuilder& Builder);
+
+private:
+ GRCoreEngine(const GRCoreEngine&); // Do not implement.
+ GRCoreEngine& operator=(const GRCoreEngine&);
+
+public:
+ /// Construct a GRCoreEngine object to analyze the provided CFG using
+ /// a DFS exploration of the exploded graph.
+ GRCoreEngine(ASTContext& ctx, GRSubEngine& subengine)
+ : SubEngine(subengine), G(new ExplodedGraph(ctx)),
+ WList(GRWorkList::MakeBFS()),
+ BCounterFactory(G->getAllocator()) {}
+
+ /// Construct a GRCoreEngine object to analyze the provided CFG and to
+ /// use the provided worklist object to execute the worklist algorithm.
+ /// The GRCoreEngine object assumes ownership of 'wlist'.
+ GRCoreEngine(ASTContext& ctx, GRWorkList* wlist, GRSubEngine& subengine)
+ : SubEngine(subengine), G(new ExplodedGraph(ctx)), WList(wlist),
+ BCounterFactory(G->getAllocator()) {}
+
+ ~GRCoreEngine() {
+ delete WList;
+ }
+
+ /// getGraph - Returns the exploded graph.
+ ExplodedGraph& getGraph() { return *G.get(); }
+
+ /// takeGraph - Returns the exploded graph. Ownership of the graph is
+ /// transfered to the caller.
+ ExplodedGraph* takeGraph() { return G.take(); }
+
+ /// ExecuteWorkList - Run the worklist algorithm for a maximum number of
+ /// steps. Returns true if there is still simulation state on the worklist.
+ bool ExecuteWorkList(const LocationContext *L, unsigned Steps);
+};
+
+class GRStmtNodeBuilder {
+ GRCoreEngine& Eng;
+ CFGBlock& B;
+ const unsigned Idx;
+ ExplodedNode* Pred;
+ ExplodedNode* LastNode;
+ GRStateManager& Mgr;
+ GRAuditor* Auditor;
+
+public:
+ bool PurgingDeadSymbols;
+ bool BuildSinks;
+ bool HasGeneratedNode;
+ ProgramPoint::Kind PointKind;
+ const void *Tag;
+
+ const GRState* CleanedState;
+
+
+ typedef llvm::SmallPtrSet<ExplodedNode*,5> DeferredTy;
+ DeferredTy Deferred;
+
+ void GenerateAutoTransition(ExplodedNode* N);
+
+public:
+ GRStmtNodeBuilder(CFGBlock* b, unsigned idx, ExplodedNode* N,
+ GRCoreEngine* e, GRStateManager &mgr);
+
+ ~GRStmtNodeBuilder();
+
+ ExplodedNode* getBasePredecessor() const { return Pred; }
+
+ ExplodedNode* getLastNode() const {
+ return LastNode ? (LastNode->isSink() ? NULL : LastNode) : NULL;
+ }
+
+ // FIXME: This should not be exposed.
+ GRWorkList *getWorkList() { return Eng.WList; }
+
+ void SetCleanedState(const GRState* St) {
+ CleanedState = St;
+ }
+
+ GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+ unsigned getCurrentBlockCount() const {
+ return getBlockCounter().getNumVisited(B.getBlockID());
+ }
+
+ ExplodedNode* generateNode(PostStmt PP,const GRState* St,ExplodedNode* Pred) {
+ HasGeneratedNode = true;
+ return generateNodeInternal(PP, St, Pred);
+ }
+
+ ExplodedNode* generateNode(const Stmt *S, const GRState *St,
+ ExplodedNode *Pred, ProgramPoint::Kind K) {
+ HasGeneratedNode = true;
+
+ if (PurgingDeadSymbols)
+ K = ProgramPoint::PostPurgeDeadSymbolsKind;
+
+ return generateNodeInternal(S, St, Pred, K, Tag);
+ }
+
+ ExplodedNode* generateNode(const Stmt *S, const GRState *St,
+ ExplodedNode *Pred) {
+ return generateNode(S, St, Pred, PointKind);
+ }
+
+ ExplodedNode*
+ generateNodeInternal(const ProgramPoint &PP, const GRState* State,
+ ExplodedNode* Pred);
+
+ ExplodedNode*
+ generateNodeInternal(const Stmt* S, const GRState* State, ExplodedNode* Pred,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+ const void *tag = 0);
+
+ /// getStmt - Return the current block-level expression associated with
+ /// this builder.
+ Stmt* getStmt() const { return B[Idx]; }
+
+ /// getBlock - Return the CFGBlock associated with the block-level expression
+ /// of this builder.
+ CFGBlock* getBlock() const { return &B; }
+
+ unsigned getIndex() const { return Idx; }
+
+ void setAuditor(GRAuditor* A) { Auditor = A; }
+
+ const GRState* GetState(ExplodedNode* Pred) const {
+ if (Pred == getBasePredecessor())
+ return CleanedState;
+ else
+ return Pred->getState();
+ }
+
+ ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred,
+ const GRState* St) {
+ return MakeNode(Dst, S, Pred, St, PointKind);
+ }
+
+ ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred,
+ const GRState* St, ProgramPoint::Kind K) {
+
+ const GRState* PredState = GetState(Pred);
+
+ // If the state hasn't changed, don't generate a new node.
+ if (!BuildSinks && St == PredState && Auditor == 0) {
+ Dst.Add(Pred);
+ return NULL;
+ }
+
+ ExplodedNode* N = generateNode(S, St, Pred, K);
+
+ if (N) {
+ if (BuildSinks)
+ N->markAsSink();
+ else {
+ if (Auditor && Auditor->Audit(N, Mgr))
+ N->markAsSink();
+
+ Dst.Add(N);
+ }
+ }
+
+ return N;
+ }
+
+ ExplodedNode* MakeSinkNode(ExplodedNodeSet& Dst, Stmt* S,
+ ExplodedNode* Pred, const GRState* St) {
+ bool Tmp = BuildSinks;
+ BuildSinks = true;
+ ExplodedNode* N = MakeNode(Dst, S, Pred, St);
+ BuildSinks = Tmp;
+ return N;
+ }
+
+};
+
+class GRBranchNodeBuilder {
+ GRCoreEngine& Eng;
+ CFGBlock* Src;
+ CFGBlock* DstT;
+ CFGBlock* DstF;
+ ExplodedNode* Pred;
+
+ typedef llvm::SmallVector<ExplodedNode*,3> DeferredTy;
+ DeferredTy Deferred;
+
+ bool GeneratedTrue;
+ bool GeneratedFalse;
+ bool InFeasibleTrue;
+ bool InFeasibleFalse;
+
+public:
+ GRBranchNodeBuilder(CFGBlock* src, CFGBlock* dstT, CFGBlock* dstF,
+ ExplodedNode* pred, GRCoreEngine* e)
+ : Eng(*e), Src(src), DstT(dstT), DstF(dstF), Pred(pred),
+ GeneratedTrue(false), GeneratedFalse(false),
+ InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {}
+
+ ~GRBranchNodeBuilder();
+
+ ExplodedNode* getPredecessor() const { return Pred; }
+
+ const ExplodedGraph& getGraph() const { return *Eng.G; }
+
+ GRBlockCounter getBlockCounter() const { return Eng.WList->getBlockCounter();}
+
+ ExplodedNode* generateNode(const GRState* State, bool branch);
+
+ CFGBlock* getTargetBlock(bool branch) const {
+ return branch ? DstT : DstF;
+ }
+
+ void markInfeasible(bool branch) {
+ if (branch)
+ InFeasibleTrue = GeneratedTrue = true;
+ else
+ InFeasibleFalse = GeneratedFalse = true;
+ }
+
+ bool isFeasible(bool branch) {
+ return branch ? !InFeasibleTrue : !InFeasibleFalse;
+ }
+
+ const GRState* getState() const {
+ return getPredecessor()->getState();
+ }
+};
+
+class GRIndirectGotoNodeBuilder {
+ GRCoreEngine& Eng;
+ CFGBlock* Src;
+ CFGBlock& DispatchBlock;
+ Expr* E;
+ ExplodedNode* Pred;
+
+public:
+ GRIndirectGotoNodeBuilder(ExplodedNode* pred, CFGBlock* src, Expr* e,
+ CFGBlock* dispatch, GRCoreEngine* eng)
+ : Eng(*eng), Src(src), DispatchBlock(*dispatch), E(e), Pred(pred) {}
+
+ class iterator {
+ CFGBlock::succ_iterator I;
+
+ friend class GRIndirectGotoNodeBuilder;
+ iterator(CFGBlock::succ_iterator i) : I(i) {}
+ public:
+
+ iterator& operator++() { ++I; return *this; }
+ bool operator!=(const iterator& X) const { return I != X.I; }
+
+ LabelStmt* getLabel() const {
+ return llvm::cast<LabelStmt>((*I)->getLabel());
+ }
+
+ CFGBlock* getBlock() const {
+ return *I;
+ }
+ };
+
+ iterator begin() { return iterator(DispatchBlock.succ_begin()); }
+ iterator end() { return iterator(DispatchBlock.succ_end()); }
+
+ ExplodedNode* generateNode(const iterator& I, const GRState* State,
+ bool isSink = false);
+
+ Expr* getTarget() const { return E; }
+
+ const GRState* getState() const { return Pred->State; }
+};
+
+class GRSwitchNodeBuilder {
+ GRCoreEngine& Eng;
+ CFGBlock* Src;
+ Expr* Condition;
+ ExplodedNode* Pred;
+
+public:
+ GRSwitchNodeBuilder(ExplodedNode* pred, CFGBlock* src,
+ Expr* condition, GRCoreEngine* eng)
+ : Eng(*eng), Src(src), Condition(condition), Pred(pred) {}
+
+ class iterator {
+ CFGBlock::succ_reverse_iterator I;
+
+ friend class GRSwitchNodeBuilder;
+ iterator(CFGBlock::succ_reverse_iterator i) : I(i) {}
+
+ public:
+ iterator& operator++() { ++I; return *this; }
+ bool operator!=(const iterator& X) const { return I != X.I; }
+
+ CaseStmt* getCase() const {
+ return llvm::cast<CaseStmt>((*I)->getLabel());
+ }
+
+ CFGBlock* getBlock() const {
+ return *I;
+ }
+ };
+
+ iterator begin() { return iterator(Src->succ_rbegin()+1); }
+ iterator end() { return iterator(Src->succ_rend()); }
+
+ ExplodedNode* generateCaseStmtNode(const iterator& I, const GRState* State);
+
+ ExplodedNode* generateDefaultCaseNode(const GRState* State,
+ bool isSink = false);
+
+ Expr* getCondition() const { return Condition; }
+
+ const GRState* getState() const { return Pred->State; }
+};
+
+class GREndPathNodeBuilder {
+ GRCoreEngine &Eng;
+ CFGBlock& B;
+ ExplodedNode* Pred;
+
+public:
+ bool HasGeneratedNode;
+
+public:
+ GREndPathNodeBuilder(CFGBlock* b, ExplodedNode* N, GRCoreEngine* e)
+ : Eng(*e), B(*b), Pred(N), HasGeneratedNode(false) {}
+
+ ~GREndPathNodeBuilder();
+
+ GRWorkList &getWorkList() { return *Eng.WList; }
+
+ ExplodedNode* getPredecessor() const { return Pred; }
+
+ GRBlockCounter getBlockCounter() const {
+ return Eng.WList->getBlockCounter();
+ }
+
+ unsigned getCurrentBlockCount() const {
+ return getBlockCounter().getNumVisited(B.getBlockID());
+ }
+
+ ExplodedNode* generateNode(const GRState* State, const void *tag = 0,
+ ExplodedNode *P = 0);
+
+ CFGBlock* getBlock() const { return &B; }
+
+ const GRState* getState() const {
+ return getPredecessor()->getState();
+ }
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRExprEngine.h b/include/clang/Checker/PathSensitive/GRExprEngine.h
new file mode 100644
index 0000000..90a2cd5
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRExprEngine.h
@@ -0,0 +1,422 @@
+//===-- GRExprEngine.h - Path-Sensitive Expression-Level Dataflow ---*- 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 a meta-engine for path-sensitive dataflow analysis that
+// is built on GRCoreEngine, but provides the boilerplate to execute transfer
+// functions and build the ExplodedGraph at the expression level.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE
+#define LLVM_CLANG_ANALYSIS_GREXPRENGINE
+
+#include "clang/Checker/PathSensitive/AnalysisManager.h"
+#include "clang/Checker/PathSensitive/GRSubEngine.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include "clang/Checker/PathSensitive/GRSimpleAPICheck.h"
+#include "clang/Checker/PathSensitive/GRTransferFuncs.h"
+#include "clang/Checker/BugReporter/BugReporter.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/AST/ExprCXX.h"
+
+namespace clang {
+
+ class PathDiagnosticClient;
+ class Diagnostic;
+ class ObjCForCollectionStmt;
+ class Checker;
+
+class GRExprEngine : public GRSubEngine {
+ AnalysisManager &AMgr;
+
+ GRCoreEngine CoreEngine;
+
+ /// G - the simulation graph.
+ ExplodedGraph& G;
+
+ /// Builder - The current GRStmtNodeBuilder which is used when building the
+ /// nodes for a given statement.
+ GRStmtNodeBuilder* Builder;
+
+ /// StateMgr - Object that manages the data for all created states.
+ GRStateManager StateMgr;
+
+ /// SymMgr - Object that manages the symbol information.
+ SymbolManager& SymMgr;
+
+ /// ValMgr - Object that manages/creates SVals.
+ ValueManager &ValMgr;
+
+ /// SVator - SValuator object that creates SVals from expressions.
+ SValuator &SVator;
+
+ /// EntryNode - The immediate predecessor node.
+ ExplodedNode* EntryNode;
+
+ /// CleanedState - The state for EntryNode "cleaned" of all dead
+ /// variables and symbols (as determined by a liveness analysis).
+ const GRState* CleanedState;
+
+ /// CurrentStmt - The current block-level statement.
+ Stmt* CurrentStmt;
+
+ // Obj-C Class Identifiers.
+ IdentifierInfo* NSExceptionII;
+
+ // Obj-C Selectors.
+ Selector* NSExceptionInstanceRaiseSelectors;
+ Selector RaiseSel;
+
+ llvm::OwningPtr<GRSimpleAPICheck> BatchAuditor;
+
+ typedef llvm::DenseMap<void *, unsigned> CheckerMap;
+ CheckerMap CheckerM;
+
+ typedef std::vector<std::pair<void *, Checker*> > CheckersOrdered;
+ CheckersOrdered Checkers;
+
+ /// BR - The BugReporter associated with this engine. It is important that
+ // this object be placed at the very end of member variables so that its
+ // destructor is called before the rest of the GRExprEngine is destroyed.
+ GRBugReporter BR;
+
+ llvm::OwningPtr<GRTransferFuncs> TF;
+
+public:
+ GRExprEngine(AnalysisManager &mgr, GRTransferFuncs *tf);
+
+ ~GRExprEngine();
+
+ void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
+ CoreEngine.ExecuteWorkList(L, Steps);
+ }
+
+ /// getContext - Return the ASTContext associated with this analysis.
+ ASTContext& getContext() const { return G.getContext(); }
+
+ AnalysisManager &getAnalysisManager() const { return AMgr; }
+
+ SValuator &getSValuator() { return SVator; }
+
+ GRTransferFuncs& getTF() { return *TF; }
+
+ BugReporter& getBugReporter() { return BR; }
+
+ GRStmtNodeBuilder &getBuilder() { assert(Builder); return *Builder; }
+
+ // FIXME: Remove once GRTransferFuncs is no longer referenced.
+ void setTransferFunction(GRTransferFuncs* tf);
+
+ /// ViewGraph - Visualize the ExplodedGraph created by executing the
+ /// simulation.
+ void ViewGraph(bool trim = false);
+
+ void ViewGraph(ExplodedNode** Beg, ExplodedNode** End);
+
+ /// getInitialState - Return the initial state used for the root vertex
+ /// in the ExplodedGraph.
+ const GRState* getInitialState(const LocationContext *InitLoc);
+
+ ExplodedGraph& getGraph() { return G; }
+ const ExplodedGraph& getGraph() const { return G; }
+
+ template <typename CHECKER>
+ void registerCheck(CHECKER *check) {
+ unsigned entry = Checkers.size();
+ void *tag = CHECKER::getTag();
+ Checkers.push_back(std::make_pair(tag, check));
+ CheckerM[tag] = entry;
+ }
+
+ Checker *lookupChecker(void *tag) const;
+
+ template <typename CHECKER>
+ CHECKER *getChecker() const {
+ return static_cast<CHECKER*>(lookupChecker(CHECKER::getTag()));
+ }
+
+ void AddCheck(GRSimpleAPICheck* A, Stmt::StmtClass C);
+ void AddCheck(GRSimpleAPICheck* A);
+
+ /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
+ /// nodes by processing the 'effects' of a block-level statement.
+ void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder);
+
+ /// ProcessBlockEntrance - Called by GRCoreEngine when start processing
+ /// a CFGBlock. This method returns true if the analysis should continue
+ /// exploring the given path, and false otherwise.
+ bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
+ GRBlockCounter BC);
+
+ /// ProcessBranch - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a branch condition.
+ void ProcessBranch(Stmt* Condition, Stmt* Term, GRBranchNodeBuilder& builder);
+
+ /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a computed goto jump.
+ void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder);
+
+ /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a switch statement.
+ void ProcessSwitch(GRSwitchNodeBuilder& builder);
+
+ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
+ /// nodes when the control reaches the end of a function.
+ void ProcessEndPath(GREndPathNodeBuilder& builder);
+
+ /// EvalAssume - Callback function invoked by the ConstraintManager when
+ /// making assumptions about state values.
+ const GRState *ProcessAssume(const GRState *state, SVal cond, bool assumption);
+
+ GRStateManager& getStateManager() { return StateMgr; }
+ const GRStateManager& getStateManager() const { return StateMgr; }
+
+ StoreManager& getStoreManager() { return StateMgr.getStoreManager(); }
+
+ ConstraintManager& getConstraintManager() {
+ return StateMgr.getConstraintManager();
+ }
+
+ // FIXME: Remove when we migrate over to just using ValueManager.
+ BasicValueFactory& getBasicVals() {
+ return StateMgr.getBasicVals();
+ }
+ const BasicValueFactory& getBasicVals() const {
+ return StateMgr.getBasicVals();
+ }
+
+ ValueManager &getValueManager() { return ValMgr; }
+ const ValueManager &getValueManager() const { return ValMgr; }
+
+ // FIXME: Remove when we migrate over to just using ValueManager.
+ SymbolManager& getSymbolManager() { return SymMgr; }
+ const SymbolManager& getSymbolManager() const { return SymMgr; }
+
+protected:
+ const GRState* GetState(ExplodedNode* N) {
+ return N == EntryNode ? CleanedState : N->getState();
+ }
+
+public:
+ ExplodedNode* MakeNode(ExplodedNodeSet& Dst, Stmt* S, ExplodedNode* Pred,
+ const GRState* St,
+ ProgramPoint::Kind K = ProgramPoint::PostStmtKind,
+ const void *tag = 0);
+protected:
+ /// CheckerVisit - Dispatcher for performing checker-specific logic
+ /// at specific statements.
+ void CheckerVisit(Stmt *S, ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
+ bool isPrevisit);
+
+ bool CheckerEvalCall(const CallExpr *CE,
+ ExplodedNodeSet &Dst,
+ ExplodedNode *Pred);
+
+ void CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
+ ExplodedNodeSet &Dst,
+ const GRState *state,
+ ExplodedNode *Pred);
+
+ void CheckerVisitBind(const Stmt *AssignE, const Stmt *StoreE,
+ ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
+ SVal location, SVal val, bool isPrevisit);
+
+
+ /// Visit - Transfer function logic for all statements. Dispatches to
+ /// other functions that handle specific kinds of statements.
+ void Visit(Stmt* S, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+ /// VisitLValue - Evaluate the lvalue of the expression. For example, if Ex is
+ /// a DeclRefExpr, it evaluates to the MemRegionVal which represents its
+ /// storage location. Note that not all kinds of expressions has lvalue.
+ void VisitLValue(Expr* Ex, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+ /// VisitArraySubscriptExpr - Transfer function for array accesses.
+ void VisitArraySubscriptExpr(ArraySubscriptExpr* Ex, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+ /// VisitAsmStmt - Transfer function logic for inline asm.
+ void VisitAsmStmt(AsmStmt* A, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+ void VisitAsmStmtHelperOutputs(AsmStmt* A,
+ AsmStmt::outputs_iterator I,
+ AsmStmt::outputs_iterator E,
+ ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+ void VisitAsmStmtHelperInputs(AsmStmt* A,
+ AsmStmt::inputs_iterator I,
+ AsmStmt::inputs_iterator E,
+ ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+ /// VisitBlockExpr - Transfer function logic for BlockExprs.
+ void VisitBlockExpr(BlockExpr *BE, ExplodedNode *Pred, ExplodedNodeSet &Dst);
+
+ /// VisitBinaryOperator - Transfer function logic for binary operators.
+ void VisitBinaryOperator(BinaryOperator* B, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+
+ /// VisitCall - Transfer function for function calls.
+ void VisitCall(CallExpr* CE, ExplodedNode* Pred,
+ CallExpr::arg_iterator AI, CallExpr::arg_iterator AE,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+ /// VisitCast - Transfer function logic for all casts (implicit and explicit).
+ void VisitCast(CastExpr *CastE, Expr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst, bool asLValue);
+
+ /// VisitCompoundLiteralExpr - Transfer function logic for compound literals.
+ void VisitCompoundLiteralExpr(CompoundLiteralExpr* CL, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+ /// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
+ void VisitDeclRefExpr(DeclRefExpr* DR, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+ /// VisitBlockDeclRefExpr - Transfer function logic for BlockDeclRefExprs.
+ void VisitBlockDeclRefExpr(BlockDeclRefExpr* DR, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+ void VisitCommonDeclRefExpr(Expr* DR, const NamedDecl *D,ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+ /// VisitDeclStmt - Transfer function logic for DeclStmts.
+ void VisitDeclStmt(DeclStmt* DS, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+ /// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
+ void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
+
+ /// VisitCondInit - Transfer function for handling the initialization
+ /// of a condition variable in an IfStmt, SwitchStmt, etc.
+ void VisitCondInit(VarDecl *VD, Stmt *S, ExplodedNode *Pred,
+ ExplodedNodeSet& Dst);
+
+ void VisitInitListExpr(InitListExpr* E, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
+
+ /// VisitLogicalExpr - Transfer function logic for '&&', '||'
+ void VisitLogicalExpr(BinaryOperator* B, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
+
+ /// VisitMemberExpr - Transfer function for member expressions.
+ void VisitMemberExpr(MemberExpr* M, ExplodedNode* Pred, ExplodedNodeSet& Dst,
+ bool asLValue);
+
+ /// VisitObjCIvarRefExpr - Transfer function logic for ObjCIvarRefExprs.
+ void VisitObjCIvarRefExpr(ObjCIvarRefExpr* DR, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+ /// VisitObjCForCollectionStmt - Transfer function logic for
+ /// ObjCForCollectionStmt.
+ void VisitObjCForCollectionStmt(ObjCForCollectionStmt* S, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
+
+ void VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
+ ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, SVal ElementV);
+
+ /// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
+ void VisitObjCMessageExpr(ObjCMessageExpr* ME, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+ /// VisitReturnStmt - Transfer function logic for return statements.
+ void VisitReturnStmt(ReturnStmt* R, ExplodedNode* Pred, ExplodedNodeSet& Dst);
+
+ /// VisitSizeOfAlignOfExpr - Transfer function for sizeof.
+ void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr* Ex, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst);
+
+ /// VisitUnaryOperator - Transfer function logic for unary operators.
+ void VisitUnaryOperator(UnaryOperator* B, ExplodedNode* Pred,
+ ExplodedNodeSet& Dst, bool asLValue);
+
+ void VisitCXXThisExpr(CXXThisExpr *TE, ExplodedNode *Pred,
+ ExplodedNodeSet & Dst);
+
+ /// Create a C++ temporary object for an rvalue.
+ void CreateCXXTemporaryObject(Expr *Ex, ExplodedNode *Pred,
+ ExplodedNodeSet &Dst);
+
+ /// EvalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic
+ /// expressions of the form 'x != 0' and generate new nodes (stored in Dst)
+ /// with those assumptions.
+ void EvalEagerlyAssume(ExplodedNodeSet& Dst, ExplodedNodeSet& Src, Expr *Ex);
+
+ SVal EvalMinus(SVal X) {
+ return X.isValid() ? SVator.EvalMinus(cast<NonLoc>(X)) : X;
+ }
+
+ SVal EvalComplement(SVal X) {
+ return X.isValid() ? SVator.EvalComplement(cast<NonLoc>(X)) : X;
+ }
+
+public:
+
+ SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ NonLoc L, NonLoc R, QualType T) {
+ return SVator.EvalBinOpNN(state, op, L, R, T);
+ }
+
+ SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode op,
+ NonLoc L, SVal R, QualType T) {
+ return R.isValid() ? SVator.EvalBinOpNN(state,op,L, cast<NonLoc>(R), T) : R;
+ }
+
+ SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
+ SVal LHS, SVal RHS, QualType T) {
+ return SVator.EvalBinOp(ST, Op, LHS, RHS, T);
+ }
+
+protected:
+ void EvalObjCMessageExpr(ExplodedNodeSet& Dst, ObjCMessageExpr* ME,
+ ExplodedNode* Pred, const GRState *state) {
+ assert (Builder && "GRStmtNodeBuilder must be defined.");
+ getTF().EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred, state);
+ }
+
+ const GRState* MarkBranch(const GRState* St, Stmt* Terminator,
+ bool branchTaken);
+
+ /// EvalBind - Handle the semantics of binding a value to a specific location.
+ /// This method is used by EvalStore, VisitDeclStmt, and others.
+ void EvalBind(ExplodedNodeSet& Dst, Stmt *AssignE,
+ Stmt* StoreE, ExplodedNode* Pred,
+ const GRState* St, SVal location, SVal Val,
+ bool atDeclInit = false);
+
+public:
+ // FIXME: 'tag' should be removed, and a LocationContext should be used
+ // instead.
+ void EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
+ const GRState* St, SVal location, const void *tag = 0,
+ QualType LoadTy = QualType());
+
+ // FIXME: 'tag' should be removed, and a LocationContext should be used
+ // instead.
+ void EvalStore(ExplodedNodeSet& Dst, Expr* AssignE, Expr* StoreE,
+ ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val,
+ const void *tag = 0);
+private:
+ void EvalLoadCommon(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
+ const GRState* St, SVal location, const void *tag,
+ QualType LoadTy);
+
+ // FIXME: 'tag' should be removed, and a LocationContext should be used
+ // instead.
+ void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred,
+ const GRState* St, SVal location,
+ const void *tag, bool isLoad);
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h b/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h
new file mode 100644
index 0000000..5503412
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRExprEngineBuilders.h
@@ -0,0 +1,76 @@
+//===-- GRExprEngineBuilders.h - "Builder" classes for GRExprEngine -*- 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 smart builder "references" which are used to marshal
+// builders between GRExprEngine objects and their related components.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
+#define LLVM_CLANG_ANALYSIS_GREXPRENGINE_BUILDERS
+#include "clang/Checker/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/Support/SaveAndRestore.h"
+
+namespace clang {
+
+class GRStmtNodeBuilderRef {
+ ExplodedNodeSet &Dst;
+ GRStmtNodeBuilder &B;
+ GRExprEngine& Eng;
+ ExplodedNode* Pred;
+ const GRState* state;
+ const Stmt* stmt;
+ const unsigned OldSize;
+ const bool AutoCreateNode;
+ SaveAndRestore<bool> OldSink;
+ SaveAndRestore<const void*> OldTag;
+ SaveOr OldHasGen;
+
+private:
+ friend class GRExprEngine;
+
+ GRStmtNodeBuilderRef(); // do not implement
+ void operator=(const GRStmtNodeBuilderRef&); // do not implement
+
+ GRStmtNodeBuilderRef(ExplodedNodeSet &dst,
+ GRStmtNodeBuilder &builder,
+ GRExprEngine& eng,
+ ExplodedNode* pred,
+ const GRState *st,
+ const Stmt* s, bool auto_create_node)
+ : Dst(dst), B(builder), Eng(eng), Pred(pred),
+ state(st), stmt(s), OldSize(Dst.size()), AutoCreateNode(auto_create_node),
+ OldSink(B.BuildSinks), OldTag(B.Tag), OldHasGen(B.HasGeneratedNode) {}
+
+public:
+
+ ~GRStmtNodeBuilderRef() {
+ // Handle the case where no nodes where generated. Auto-generate that
+ // contains the updated state if we aren't generating sinks.
+ if (!B.BuildSinks && Dst.size() == OldSize && !B.HasGeneratedNode) {
+ if (AutoCreateNode)
+ B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
+ else
+ Dst.Add(Pred);
+ }
+ }
+
+ const GRState *getState() { return state; }
+
+ GRStateManager& getStateManager() {
+ return Eng.getStateManager();
+ }
+
+ ExplodedNode* MakeNode(const GRState* state) {
+ return B.MakeNode(Dst, const_cast<Stmt*>(stmt), Pred, state);
+ }
+};
+
+} // end clang namespace
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
new file mode 100644
index 0000000..383463b
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRSimpleAPICheck.h
@@ -0,0 +1,40 @@
+// GRCheckAPI.h - Simple API checks based on GRAuditor ------------*- 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 the interface for building simple, path-sensitive checks
+// that are stateless and only emit warnings at errors that occur at
+// CallExpr or ObjCMessageExpr.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRAPICHECKS
+#define LLVM_CLANG_ANALYSIS_GRAPICHECKS
+
+#include "clang/Checker/PathSensitive/GRAuditor.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+
+namespace clang {
+
+class Diagnostic;
+class BugReporter;
+class ASTContext;
+class GRExprEngine;
+class PathDiagnosticClient;
+class ExplodedGraph;
+
+
+class GRSimpleAPICheck : public GRAuditor {
+public:
+ GRSimpleAPICheck() {}
+ virtual ~GRSimpleAPICheck() {}
+};
+
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRState.h b/include/clang/Checker/PathSensitive/GRState.h
new file mode 100644
index 0000000..4e44697
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRState.h
@@ -0,0 +1,756 @@
+//== GRState*h - Path-Sens. "State" for tracking valuues -----*- 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 SymbolRef, ExprBindKey, and GRState*
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_VALUESTATE_H
+#define LLVM_CLANG_ANALYSIS_VALUESTATE_H
+
+// FIXME: Reduce the number of includes.
+
+#include "clang/Checker/PathSensitive/Environment.h"
+#include "clang/Checker/PathSensitive/Store.h"
+#include "clang/Checker/PathSensitive/ConstraintManager.h"
+#include "clang/Checker/PathSensitive/ValueManager.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/System/DataTypes.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <functional>
+
+namespace clang {
+
+class GRStateManager;
+class Checker;
+
+typedef ConstraintManager* (*ConstraintManagerCreator)(GRStateManager&,
+ GRSubEngine&);
+typedef StoreManager* (*StoreManagerCreator)(GRStateManager&);
+
+//===----------------------------------------------------------------------===//
+// GRStateTrait - Traits used by the Generic Data Map of a GRState.
+//===----------------------------------------------------------------------===//
+
+template <typename T> struct GRStatePartialTrait;
+
+template <typename T> struct GRStateTrait {
+ typedef typename T::data_type data_type;
+ static inline void* GDMIndex() { return &T::TagInt; }
+ static inline void* MakeVoidPtr(data_type D) { return (void*) D; }
+ static inline data_type MakeData(void* const* P) {
+ return P ? (data_type) *P : (data_type) 0;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// GRState- An ImmutableMap type Stmt*/Decl*/Symbols to SVals.
+//===----------------------------------------------------------------------===//
+
+class GRStateManager;
+
+/// GRState - This class encapsulates the actual data values for
+/// for a "state" in our symbolic value tracking. It is intended to be
+/// used as a functional object; that is once it is created and made
+/// "persistent" in a FoldingSet its values will never change.
+class GRState : public llvm::FoldingSetNode {
+public:
+ typedef llvm::ImmutableSet<llvm::APSInt*> IntSetTy;
+ typedef llvm::ImmutableMap<void*, void*> GenericDataMap;
+
+private:
+ void operator=(const GRState& R) const;
+
+ friend class GRStateManager;
+
+ GRStateManager *StateMgr;
+ Environment Env;
+ Store St;
+
+ // FIXME: Make these private.
+public:
+ GenericDataMap GDM;
+
+public:
+
+ /// This ctor is used when creating the first GRState object.
+ GRState(GRStateManager *mgr, const Environment& env,
+ Store st, GenericDataMap gdm)
+ : StateMgr(mgr),
+ Env(env),
+ St(st),
+ GDM(gdm) {}
+
+ /// Copy ctor - We must explicitly define this or else the "Next" ptr
+ /// in FoldingSetNode will also get copied.
+ GRState(const GRState& RHS)
+ : llvm::FoldingSetNode(),
+ StateMgr(RHS.StateMgr),
+ Env(RHS.Env),
+ St(RHS.St),
+ GDM(RHS.GDM) {}
+
+ /// getStateManager - Return the GRStateManager associated with this state.
+ GRStateManager &getStateManager() const {
+ return *StateMgr;
+ }
+
+ /// getAnalysisContext - Return the AnalysisContext associated with this
+ /// state.
+ AnalysisContext &getAnalysisContext() const {
+ return Env.getAnalysisContext();
+ }
+
+ /// getEnvironment - Return the environment associated with this state.
+ /// The environment is the mapping from expressions to values.
+ const Environment& getEnvironment() const { return Env; }
+
+ /// getStore - Return the store associated with this state. The store
+ /// is a mapping from locations to values.
+ Store getStore() const { return St; }
+
+ void setStore(Store s) { St = s; }
+
+ /// getGDM - Return the generic data map associated with this state.
+ GenericDataMap getGDM() const { return GDM; }
+
+ void setGDM(GenericDataMap gdm) { GDM = gdm; }
+
+ /// Profile - Profile the contents of a GRState object for use
+ /// in a FoldingSet.
+ static void Profile(llvm::FoldingSetNodeID& ID, const GRState* V) {
+ // FIXME: Do we need to include the AnalysisContext in the profile?
+ V->Env.Profile(ID);
+ ID.AddPointer(V->St);
+ V->GDM.Profile(ID);
+ }
+
+ /// Profile - Used to profile the contents of this object for inclusion
+ /// in a FoldingSet.
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Profile(ID, this);
+ }
+
+ SVal LookupExpr(Expr* E) const {
+ return Env.LookupExpr(E);
+ }
+
+ /// makeWithStore - Return a GRState with the same values as the current
+ /// state with the exception of using the specified Store.
+ const GRState *makeWithStore(Store store) const;
+
+ BasicValueFactory &getBasicVals() const;
+ SymbolManager &getSymbolManager() const;
+
+ //==---------------------------------------------------------------------==//
+ // Constraints on values.
+ //==---------------------------------------------------------------------==//
+ //
+ // Each GRState records constraints on symbolic values. These constraints
+ // are managed using the ConstraintManager associated with a GRStateManager.
+ // As constraints gradually accrue on symbolic values, added constraints
+ // may conflict and indicate that a state is infeasible (as no real values
+ // could satisfy all the constraints). This is the principal mechanism
+ // for modeling path-sensitivity in GRExprEngine/GRState.
+ //
+ // Various "Assume" methods form the interface for adding constraints to
+ // symbolic values. A call to "Assume" indicates an assumption being placed
+ // on one or symbolic values. Assume methods take the following inputs:
+ //
+ // (1) A GRState object representing the current state.
+ //
+ // (2) The assumed constraint (which is specific to a given "Assume" method).
+ //
+ // (3) A binary value "Assumption" that indicates whether the constraint is
+ // assumed to be true or false.
+ //
+ // The output of "Assume" are two values:
+ //
+ // (a) "isFeasible" is set to true or false to indicate whether or not
+ // the assumption is feasible.
+ //
+ // (b) A new GRState object with the added constraints.
+ //
+ // FIXME: (a) should probably disappear since it is redundant with (b).
+ // (i.e., (b) could just be set to NULL).
+ //
+
+ const GRState *Assume(DefinedOrUnknownSVal cond, bool assumption) const;
+
+ std::pair<const GRState*, const GRState*>
+ Assume(DefinedOrUnknownSVal cond) const;
+
+ const GRState *AssumeInBound(DefinedOrUnknownSVal idx,
+ DefinedOrUnknownSVal upperBound,
+ bool assumption) const;
+
+ //==---------------------------------------------------------------------==//
+ // Utility methods for getting regions.
+ //==---------------------------------------------------------------------==//
+
+ const VarRegion* getRegion(const VarDecl *D, const LocationContext *LC) const;
+
+ //==---------------------------------------------------------------------==//
+ // Binding and retrieving values to/from the environment and symbolic store.
+ //==---------------------------------------------------------------------==//
+
+ /// BindCompoundLiteral - Return the state that has the bindings currently
+ /// in 'state' plus the bindings for the CompoundLiteral. 'R' is the region
+ /// for the compound literal and 'BegInit' and 'EndInit' represent an
+ /// array of initializer values.
+ const GRState *bindCompoundLiteral(const CompoundLiteralExpr* CL,
+ const LocationContext *LC,
+ SVal V) const;
+
+ const GRState *BindExpr(const Stmt *S, SVal V, bool Invalidate = true) const;
+
+ const GRState *bindDecl(const VarRegion *VR, SVal V) const;
+
+ const GRState *bindDeclWithNoInit(const VarRegion *VR) const;
+
+ const GRState *bindLoc(Loc location, SVal V) const;
+
+ const GRState *bindLoc(SVal location, SVal V) const;
+
+ const GRState *unbindLoc(Loc LV) const;
+
+ /// Get the lvalue for a variable reference.
+ SVal getLValue(const VarDecl *D, const LocationContext *LC) const;
+
+ /// Get the lvalue for a StringLiteral.
+ SVal getLValue(const StringLiteral *literal) const;
+
+ SVal getLValue(const CompoundLiteralExpr *literal,
+ const LocationContext *LC) const;
+
+ /// Get the lvalue for an ivar reference.
+ SVal getLValue(const ObjCIvarDecl *decl, SVal base) const;
+
+ /// Get the lvalue for a field reference.
+ SVal getLValue(const FieldDecl *decl, SVal Base) const;
+
+ /// Get the lvalue for an array index.
+ SVal getLValue(QualType ElementType, SVal Idx, SVal Base) const;
+
+ const llvm::APSInt *getSymVal(SymbolRef sym) const;
+
+ SVal getSVal(const Stmt* Ex) const;
+
+ SVal getSValAsScalarOrLoc(const Stmt *Ex) const;
+
+ SVal getSVal(Loc LV, QualType T = QualType()) const;
+
+ SVal getSVal(const MemRegion* R) const;
+
+ SVal getSValAsScalarOrLoc(const MemRegion *R) const;
+
+ const llvm::APSInt *getSymVal(SymbolRef sym);
+
+ bool scanReachableSymbols(SVal val, SymbolVisitor& visitor) const;
+
+ bool scanReachableSymbols(const SVal *I, const SVal *E,
+ SymbolVisitor &visitor) const;
+
+ bool scanReachableSymbols(const MemRegion * const *I,
+ const MemRegion * const *E,
+ SymbolVisitor &visitor) const;
+
+ template <typename CB> CB scanReachableSymbols(SVal val) const;
+ template <typename CB> CB scanReachableSymbols(const SVal *beg,
+ const SVal *end) const;
+
+ template <typename CB> CB
+ scanReachableSymbols(const MemRegion * const *beg,
+ const MemRegion * const *end) const;
+
+ //==---------------------------------------------------------------------==//
+ // Accessing the Generic Data Map (GDM).
+ //==---------------------------------------------------------------------==//
+
+ void* const* FindGDM(void* K) const;
+
+ template<typename T>
+ const GRState *add(typename GRStateTrait<T>::key_type K) const;
+
+ template <typename T>
+ typename GRStateTrait<T>::data_type
+ get() const {
+ return GRStateTrait<T>::MakeData(FindGDM(GRStateTrait<T>::GDMIndex()));
+ }
+
+ template<typename T>
+ typename GRStateTrait<T>::lookup_type
+ get(typename GRStateTrait<T>::key_type key) const {
+ void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
+ return GRStateTrait<T>::Lookup(GRStateTrait<T>::MakeData(d), key);
+ }
+
+ template <typename T>
+ typename GRStateTrait<T>::context_type get_context() const;
+
+
+ template<typename T>
+ const GRState *remove(typename GRStateTrait<T>::key_type K) const;
+
+ template<typename T>
+ const GRState *remove(typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::context_type C) const;
+
+ template<typename T>
+ const GRState *set(typename GRStateTrait<T>::data_type D) const;
+
+ template<typename T>
+ const GRState *set(typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::value_type E) const;
+
+ template<typename T>
+ const GRState *set(typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::value_type E,
+ typename GRStateTrait<T>::context_type C) const;
+
+ template<typename T>
+ bool contains(typename GRStateTrait<T>::key_type key) const {
+ void* const* d = FindGDM(GRStateTrait<T>::GDMIndex());
+ return GRStateTrait<T>::Contains(GRStateTrait<T>::MakeData(d), key);
+ }
+
+ // State pretty-printing.
+ class Printer {
+ public:
+ virtual ~Printer() {}
+ virtual void Print(llvm::raw_ostream& Out, const GRState* state,
+ const char* nl, const char* sep) = 0;
+ };
+
+ // Pretty-printing.
+ void print(llvm::raw_ostream& Out, const char *nl = "\n",
+ const char *sep = "") const;
+
+ void printStdErr() const;
+
+ void printDOT(llvm::raw_ostream& Out) const;
+};
+
+class GRStateSet {
+ typedef llvm::SmallPtrSet<const GRState*,5> ImplTy;
+ ImplTy Impl;
+public:
+ GRStateSet() {}
+
+ inline void Add(const GRState* St) {
+ Impl.insert(St);
+ }
+
+ typedef ImplTy::const_iterator iterator;
+
+ inline unsigned size() const { return Impl.size(); }
+ inline bool empty() const { return Impl.empty(); }
+
+ inline iterator begin() const { return Impl.begin(); }
+ inline iterator end() const { return Impl.end(); }
+
+ class AutoPopulate {
+ GRStateSet& S;
+ unsigned StartSize;
+ const GRState* St;
+ public:
+ AutoPopulate(GRStateSet& s, const GRState* st)
+ : S(s), StartSize(S.size()), St(st) {}
+
+ ~AutoPopulate() {
+ if (StartSize == S.size())
+ S.Add(St);
+ }
+ };
+};
+
+//===----------------------------------------------------------------------===//
+// GRStateManager - Factory object for GRStates.
+//===----------------------------------------------------------------------===//
+
+class GRStateManager {
+ friend class GRState;
+ friend class GRExprEngine; // FIXME: Remove.
+private:
+ EnvironmentManager EnvMgr;
+ llvm::OwningPtr<StoreManager> StoreMgr;
+ llvm::OwningPtr<ConstraintManager> ConstraintMgr;
+
+ GRState::GenericDataMap::Factory GDMFactory;
+
+ typedef llvm::DenseMap<void*,std::pair<void*,void (*)(void*)> > GDMContextsTy;
+ GDMContextsTy GDMContexts;
+
+ /// Printers - A set of printer objects used for pretty-printing a GRState.
+ /// GRStateManager owns these objects.
+ std::vector<GRState::Printer*> Printers;
+
+ /// StateSet - FoldingSet containing all the states created for analyzing
+ /// a particular function. This is used to unique states.
+ llvm::FoldingSet<GRState> StateSet;
+
+ /// ValueMgr - Object that manages the data for all created SVals.
+ ValueManager ValueMgr;
+
+ /// Alloc - A BumpPtrAllocator to allocate states.
+ llvm::BumpPtrAllocator &Alloc;
+
+public:
+ GRStateManager(ASTContext& Ctx,
+ StoreManagerCreator CreateStoreManager,
+ ConstraintManagerCreator CreateConstraintManager,
+ llvm::BumpPtrAllocator& alloc,
+ GRSubEngine &subeng)
+ : EnvMgr(alloc),
+ GDMFactory(alloc),
+ ValueMgr(alloc, Ctx, *this),
+ Alloc(alloc) {
+ StoreMgr.reset((*CreateStoreManager)(*this));
+ ConstraintMgr.reset((*CreateConstraintManager)(*this, subeng));
+ }
+
+ ~GRStateManager();
+
+ const GRState *getInitialState(const LocationContext *InitLoc);
+
+ ASTContext &getContext() { return ValueMgr.getContext(); }
+ const ASTContext &getContext() const { return ValueMgr.getContext(); }
+
+ BasicValueFactory &getBasicVals() {
+ return ValueMgr.getBasicValueFactory();
+ }
+ const BasicValueFactory& getBasicVals() const {
+ return ValueMgr.getBasicValueFactory();
+ }
+
+ SymbolManager &getSymbolManager() {
+ return ValueMgr.getSymbolManager();
+ }
+ const SymbolManager &getSymbolManager() const {
+ return ValueMgr.getSymbolManager();
+ }
+
+ ValueManager &getValueManager() { return ValueMgr; }
+ const ValueManager &getValueManager() const { return ValueMgr; }
+
+ llvm::BumpPtrAllocator& getAllocator() { return Alloc; }
+
+ MemRegionManager& getRegionManager() {
+ return ValueMgr.getRegionManager();
+ }
+ const MemRegionManager& getRegionManager() const {
+ return ValueMgr.getRegionManager();
+ }
+
+ StoreManager& getStoreManager() { return *StoreMgr; }
+ ConstraintManager& getConstraintManager() { return *ConstraintMgr; }
+
+ const GRState* RemoveDeadBindings(const GRState* St, Stmt* Loc,
+ SymbolReaper& SymReaper);
+
+public:
+
+ SVal ArrayToPointer(Loc Array) {
+ return StoreMgr->ArrayToPointer(Array);
+ }
+
+ // Methods that manipulate the GDM.
+ const GRState* addGDM(const GRState* St, void* Key, void* Data);
+
+ // Methods that query & manipulate the Store.
+
+ void iterBindings(const GRState* state, StoreManager::BindingsHandler& F) {
+ StoreMgr->iterBindings(state->getStore(), F);
+ }
+
+ const GRState* getPersistentState(GRState& Impl);
+
+ bool isEqual(const GRState* state, const Expr* Ex, const llvm::APSInt& V);
+ bool isEqual(const GRState* state, const Expr* Ex, uint64_t);
+
+ //==---------------------------------------------------------------------==//
+ // Generic Data Map methods.
+ //==---------------------------------------------------------------------==//
+ //
+ // GRStateManager and GRState support a "generic data map" that allows
+ // different clients of GRState objects to embed arbitrary data within a
+ // GRState object. The generic data map is essentially an immutable map
+ // from a "tag" (that acts as the "key" for a client) and opaque values.
+ // Tags/keys and values are simply void* values. The typical way that clients
+ // generate unique tags are by taking the address of a static variable.
+ // Clients are responsible for ensuring that data values referred to by a
+ // the data pointer are immutable (and thus are essentially purely functional
+ // data).
+ //
+ // The templated methods below use the GRStateTrait<T> class
+ // to resolve keys into the GDM and to return data values to clients.
+ //
+
+ // Trait based GDM dispatch.
+ template <typename T>
+ const GRState* set(const GRState* st, typename GRStateTrait<T>::data_type D) {
+ return addGDM(st, GRStateTrait<T>::GDMIndex(),
+ GRStateTrait<T>::MakeVoidPtr(D));
+ }
+
+ template<typename T>
+ const GRState* set(const GRState* st,
+ typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::value_type V,
+ typename GRStateTrait<T>::context_type C) {
+
+ return addGDM(st, GRStateTrait<T>::GDMIndex(),
+ GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Set(st->get<T>(), K, V, C)));
+ }
+
+ template <typename T>
+ const GRState* add(const GRState* st,
+ typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::context_type C) {
+ return addGDM(st, GRStateTrait<T>::GDMIndex(),
+ GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Add(st->get<T>(), K, C)));
+ }
+
+ template <typename T>
+ const GRState* remove(const GRState* st,
+ typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::context_type C) {
+
+ return addGDM(st, GRStateTrait<T>::GDMIndex(),
+ GRStateTrait<T>::MakeVoidPtr(GRStateTrait<T>::Remove(st->get<T>(), K, C)));
+ }
+
+
+ void* FindGDMContext(void* index,
+ void* (*CreateContext)(llvm::BumpPtrAllocator&),
+ void (*DeleteContext)(void*));
+
+ template <typename T>
+ typename GRStateTrait<T>::context_type get_context() {
+ void* p = FindGDMContext(GRStateTrait<T>::GDMIndex(),
+ GRStateTrait<T>::CreateContext,
+ GRStateTrait<T>::DeleteContext);
+
+ return GRStateTrait<T>::MakeContext(p);
+ }
+
+ const llvm::APSInt* getSymVal(const GRState* St, SymbolRef sym) {
+ return ConstraintMgr->getSymVal(St, sym);
+ }
+
+ void EndPath(const GRState* St) {
+ ConstraintMgr->EndPath(St);
+ }
+};
+
+
+//===----------------------------------------------------------------------===//
+// Out-of-line method definitions for GRState.
+//===----------------------------------------------------------------------===//
+
+inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) {
+ return getStateManager().getSymVal(this, sym);
+}
+
+inline const VarRegion* GRState::getRegion(const VarDecl *D,
+ const LocationContext *LC) const {
+ return getStateManager().getRegionManager().getVarRegion(D, LC);
+}
+
+inline const GRState *GRState::Assume(DefinedOrUnknownSVal Cond,
+ bool Assumption) const {
+ if (Cond.isUnknown())
+ return this;
+
+ return getStateManager().ConstraintMgr->Assume(this, cast<DefinedSVal>(Cond),
+ Assumption);
+}
+
+inline std::pair<const GRState*, const GRState*>
+GRState::Assume(DefinedOrUnknownSVal Cond) const {
+ if (Cond.isUnknown())
+ return std::make_pair(this, this);
+
+ return getStateManager().ConstraintMgr->AssumeDual(this,
+ cast<DefinedSVal>(Cond));
+}
+
+inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx,
+ DefinedOrUnknownSVal UpperBound,
+ bool Assumption) const {
+ if (Idx.isUnknown() || UpperBound.isUnknown())
+ return this;
+
+ ConstraintManager &CM = *getStateManager().ConstraintMgr;
+ return CM.AssumeInBound(this, cast<DefinedSVal>(Idx),
+ cast<DefinedSVal>(UpperBound), Assumption);
+}
+
+inline const GRState *
+GRState::bindCompoundLiteral(const CompoundLiteralExpr* CL,
+ const LocationContext *LC, SVal V) const {
+ Store new_store =
+ getStateManager().StoreMgr->BindCompoundLiteral(St, CL, LC, V);
+ return makeWithStore(new_store);
+}
+
+inline const GRState *GRState::bindDecl(const VarRegion* VR, SVal IVal) const {
+ Store new_store = getStateManager().StoreMgr->BindDecl(St, VR, IVal);
+ return makeWithStore(new_store);
+}
+
+inline const GRState *GRState::bindDeclWithNoInit(const VarRegion* VR) const {
+ Store new_store = getStateManager().StoreMgr->BindDeclWithNoInit(St, VR);
+ return makeWithStore(new_store);
+}
+
+inline const GRState *GRState::bindLoc(Loc LV, SVal V) const {
+ Store new_store = getStateManager().StoreMgr->Bind(St, LV, V);
+ return makeWithStore(new_store);
+}
+
+inline const GRState *GRState::bindLoc(SVal LV, SVal V) const {
+ return !isa<Loc>(LV) ? this : bindLoc(cast<Loc>(LV), V);
+}
+
+inline SVal GRState::getLValue(const VarDecl* VD,
+ const LocationContext *LC) const {
+ return getStateManager().StoreMgr->getLValueVar(VD, LC);
+}
+
+inline SVal GRState::getLValue(const StringLiteral *literal) const {
+ return getStateManager().StoreMgr->getLValueString(literal);
+}
+
+inline SVal GRState::getLValue(const CompoundLiteralExpr *literal,
+ const LocationContext *LC) const {
+ return getStateManager().StoreMgr->getLValueCompoundLiteral(literal, LC);
+}
+
+inline SVal GRState::getLValue(const ObjCIvarDecl *D, SVal Base) const {
+ return getStateManager().StoreMgr->getLValueIvar(D, Base);
+}
+
+inline SVal GRState::getLValue(const FieldDecl* D, SVal Base) const {
+ return getStateManager().StoreMgr->getLValueField(D, Base);
+}
+
+inline SVal GRState::getLValue(QualType ElementType, SVal Idx, SVal Base) const{
+ return getStateManager().StoreMgr->getLValueElement(ElementType, Idx, Base);
+}
+
+inline const llvm::APSInt *GRState::getSymVal(SymbolRef sym) const {
+ return getStateManager().getSymVal(this, sym);
+}
+
+inline SVal GRState::getSVal(const Stmt* Ex) const {
+ return Env.GetSVal(Ex, getStateManager().ValueMgr);
+}
+
+inline SVal GRState::getSValAsScalarOrLoc(const Stmt *S) const {
+ if (const Expr *Ex = dyn_cast<Expr>(S)) {
+ QualType T = Ex->getType();
+ if (Loc::IsLocType(T) || T->isIntegerType())
+ return getSVal(S);
+ }
+
+ return UnknownVal();
+}
+
+inline SVal GRState::getSVal(Loc LV, QualType T) const {
+ return getStateManager().StoreMgr->Retrieve(St, LV, T);
+}
+
+inline SVal GRState::getSVal(const MemRegion* R) const {
+ return getStateManager().StoreMgr->Retrieve(St, loc::MemRegionVal(R));
+}
+
+inline BasicValueFactory &GRState::getBasicVals() const {
+ return getStateManager().getBasicVals();
+}
+
+inline SymbolManager &GRState::getSymbolManager() const {
+ return getStateManager().getSymbolManager();
+}
+
+template<typename T>
+const GRState *GRState::add(typename GRStateTrait<T>::key_type K) const {
+ return getStateManager().add<T>(this, K, get_context<T>());
+}
+
+template <typename T>
+typename GRStateTrait<T>::context_type GRState::get_context() const {
+ return getStateManager().get_context<T>();
+}
+
+template<typename T>
+const GRState *GRState::remove(typename GRStateTrait<T>::key_type K) const {
+ return getStateManager().remove<T>(this, K, get_context<T>());
+}
+
+template<typename T>
+const GRState *GRState::remove(typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::context_type C) const {
+ return getStateManager().remove<T>(this, K, C);
+}
+
+template<typename T>
+const GRState *GRState::set(typename GRStateTrait<T>::data_type D) const {
+ return getStateManager().set<T>(this, D);
+}
+
+template<typename T>
+const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::value_type E) const {
+ return getStateManager().set<T>(this, K, E, get_context<T>());
+}
+
+template<typename T>
+const GRState *GRState::set(typename GRStateTrait<T>::key_type K,
+ typename GRStateTrait<T>::value_type E,
+ typename GRStateTrait<T>::context_type C) const {
+ return getStateManager().set<T>(this, K, E, C);
+}
+
+template <typename CB>
+CB GRState::scanReachableSymbols(SVal val) const {
+ CB cb(this);
+ scanReachableSymbols(val, cb);
+ return cb;
+}
+
+template <typename CB>
+CB GRState::scanReachableSymbols(const SVal *beg, const SVal *end) const {
+ CB cb(this);
+ scanReachableSymbols(beg, end, cb);
+ return cb;
+}
+
+template <typename CB>
+CB GRState::scanReachableSymbols(const MemRegion * const *beg,
+ const MemRegion * const *end) const {
+ CB cb(this);
+ scanReachableSymbols(beg, end, cb);
+ return cb;
+}
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRStateTrait.h b/include/clang/Checker/PathSensitive/GRStateTrait.h
new file mode 100644
index 0000000..5189a1f
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRStateTrait.h
@@ -0,0 +1,148 @@
+//==- GRStateTrait.h - Partial implementations of GRStateTrait -----*- 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 partial implementations of template specializations of
+// the class GRStateTrait<>. GRStateTrait<> is used by GRState to implement
+// set/get methods for mapulating a GRState's generic data map.
+//
+//===----------------------------------------------------------------------===//
+
+
+#ifndef LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H
+#define LLVM_CLANG_ANALYSIS_GRSTATETRAIT_H
+
+namespace llvm {
+ class BumpPtrAllocator;
+ template <typename K, typename D, typename I> class ImmutableMap;
+ template <typename K, typename I> class ImmutableSet;
+ template <typename T> class ImmutableList;
+ template <typename T> class ImmutableListImpl;
+}
+
+namespace clang {
+ template <typename T> struct GRStatePartialTrait;
+
+ // Partial-specialization for ImmutableMap.
+
+ template <typename Key, typename Data, typename Info>
+ struct GRStatePartialTrait< llvm::ImmutableMap<Key,Data,Info> > {
+ typedef llvm::ImmutableMap<Key,Data,Info> data_type;
+ typedef typename data_type::Factory& context_type;
+ typedef Key key_type;
+ typedef Data value_type;
+ typedef const value_type* lookup_type;
+
+ static inline data_type MakeData(void* const* p) {
+ return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
+ }
+ static inline void* MakeVoidPtr(data_type B) {
+ return B.getRoot();
+ }
+ static lookup_type Lookup(data_type B, key_type K) {
+ return B.lookup(K);
+ }
+ static data_type Set(data_type B, key_type K, value_type E,context_type F){
+ return F.Add(B, K, E);
+ }
+
+ static data_type Remove(data_type B, key_type K, context_type F) {
+ return F.Remove(B, K);
+ }
+
+ static inline context_type MakeContext(void* p) {
+ return *((typename data_type::Factory*) p);
+ }
+
+ static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ return new typename data_type::Factory(Alloc);
+ }
+
+ static void DeleteContext(void* Ctx) {
+ delete (typename data_type::Factory*) Ctx;
+ }
+ };
+
+
+ // Partial-specialization for ImmutableSet.
+
+ template <typename Key, typename Info>
+ struct GRStatePartialTrait< llvm::ImmutableSet<Key,Info> > {
+ typedef llvm::ImmutableSet<Key,Info> data_type;
+ typedef typename data_type::Factory& context_type;
+ typedef Key key_type;
+
+ static inline data_type MakeData(void* const* p) {
+ return p ? data_type((typename data_type::TreeTy*) *p) : data_type(0);
+ }
+
+ static inline void* MakeVoidPtr(data_type B) {
+ return B.getRoot();
+ }
+
+ static data_type Add(data_type B, key_type K, context_type F) {
+ return F.Add(B, K);
+ }
+
+ static data_type Remove(data_type B, key_type K, context_type F) {
+ return F.Remove(B, K);
+ }
+
+ static bool Contains(data_type B, key_type K) {
+ return B.contains(K);
+ }
+
+ static inline context_type MakeContext(void* p) {
+ return *((typename data_type::Factory*) p);
+ }
+
+ static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ return new typename data_type::Factory(Alloc);
+ }
+
+ static void DeleteContext(void* Ctx) {
+ delete (typename data_type::Factory*) Ctx;
+ }
+ };
+
+ // Partial-specialization for ImmutableList.
+
+ template <typename T>
+ struct GRStatePartialTrait< llvm::ImmutableList<T> > {
+ typedef llvm::ImmutableList<T> data_type;
+ typedef T key_type;
+ typedef typename data_type::Factory& context_type;
+
+ static data_type Add(data_type L, key_type K, context_type F) {
+ return F.Add(K, L);
+ }
+
+ static inline data_type MakeData(void* const* p) {
+ return p ? data_type((const llvm::ImmutableListImpl<T>*) *p)
+ : data_type(0);
+ }
+
+ static inline void* MakeVoidPtr(data_type D) {
+ return (void*) D.getInternalPointer();
+ }
+
+ static inline context_type MakeContext(void* p) {
+ return *((typename data_type::Factory*) p);
+ }
+
+ static void* CreateContext(llvm::BumpPtrAllocator& Alloc) {
+ return new typename data_type::Factory(Alloc);
+ }
+
+ static void DeleteContext(void* Ctx) {
+ delete (typename data_type::Factory*) Ctx;
+ }
+ };
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRSubEngine.h b/include/clang/Checker/PathSensitive/GRSubEngine.h
new file mode 100644
index 0000000..ce57c2c
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRSubEngine.h
@@ -0,0 +1,75 @@
+//== GRSubEngine.h - Interface of the subengine of GRCoreEngine ----*- 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 the interface of a subengine of the GRCoreEngine.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
+#define LLVM_CLANG_ANALYSIS_GRSUBENGINE_H
+
+#include "clang/Checker/PathSensitive/SVals.h"
+
+namespace clang {
+
+class Stmt;
+class CFGBlock;
+class CFGElement;
+class GRState;
+class GRStateManager;
+class GRBlockCounter;
+class GRStmtNodeBuilder;
+class GRBranchNodeBuilder;
+class GRIndirectGotoNodeBuilder;
+class GRSwitchNodeBuilder;
+class GREndPathNodeBuilder;
+class LocationContext;
+
+class GRSubEngine {
+public:
+ virtual ~GRSubEngine() {}
+
+ virtual const GRState* getInitialState(const LocationContext *InitLoc) = 0;
+
+ virtual GRStateManager& getStateManager() = 0;
+
+ /// ProcessStmt - Called by GRCoreEngine. Used to generate new successor
+ /// nodes by processing the 'effects' of a block-level statement.
+ virtual void ProcessStmt(CFGElement E, GRStmtNodeBuilder& builder) = 0;
+
+ /// ProcessBlockEntrance - Called by GRCoreEngine when start processing
+ /// a CFGBlock. This method returns true if the analysis should continue
+ /// exploring the given path, and false otherwise.
+ virtual bool ProcessBlockEntrance(CFGBlock* B, const GRState* St,
+ GRBlockCounter BC) = 0;
+
+ /// ProcessBranch - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a branch condition.
+ virtual void ProcessBranch(Stmt* Condition, Stmt* Term,
+ GRBranchNodeBuilder& builder) = 0;
+
+ /// ProcessIndirectGoto - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a computed goto jump.
+ virtual void ProcessIndirectGoto(GRIndirectGotoNodeBuilder& builder) = 0;
+
+ /// ProcessSwitch - Called by GRCoreEngine. Used to generate successor
+ /// nodes by processing the 'effects' of a switch statement.
+ virtual void ProcessSwitch(GRSwitchNodeBuilder& builder) = 0;
+
+ /// ProcessEndPath - Called by GRCoreEngine. Used to generate end-of-path
+ /// nodes when the control reaches the end of a function.
+ virtual void ProcessEndPath(GREndPathNodeBuilder& builder) = 0;
+
+ /// EvalAssume - Called by ConstraintManager. Used to call checker-specific
+ /// logic for handling assumptions on symbolic values.
+ virtual const GRState* ProcessAssume(const GRState *state,
+ SVal cond, bool assumption) = 0;
+};
+}
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRTransferFuncs.h b/include/clang/Checker/PathSensitive/GRTransferFuncs.h
new file mode 100644
index 0000000..04634ef
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRTransferFuncs.h
@@ -0,0 +1,85 @@
+//== GRTransferFuncs.h - Path-Sens. Transfer Functions Interface -*- 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 GRTransferFuncs, which provides a base-class that
+// defines an interface for transfer functions used by GRExprEngine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRTF
+#define LLVM_CLANG_ANALYSIS_GRTF
+
+#include "clang/Checker/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/GRCoreEngine.h"
+#include "clang/Checker/PathSensitive/GRState.h"
+#include <vector>
+
+namespace clang {
+
+class GRExprEngine;
+class ObjCMessageExpr;
+class GRStmtNodeBuilderRef;
+
+class GRTransferFuncs {
+public:
+ GRTransferFuncs() {}
+ virtual ~GRTransferFuncs() {}
+
+ virtual void RegisterPrinters(std::vector<GRState::Printer*>& Printers) {}
+ virtual void RegisterChecks(GRExprEngine& Eng) {}
+
+
+ // Calls.
+
+ virtual void EvalCall(ExplodedNodeSet& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder& Builder,
+ CallExpr* CE, SVal L,
+ ExplodedNode* Pred) {}
+
+ virtual void EvalObjCMessageExpr(ExplodedNodeSet& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder& Builder,
+ ObjCMessageExpr* ME,
+ ExplodedNode* Pred,
+ const GRState *state) {}
+
+ // Stores.
+
+ virtual void EvalBind(GRStmtNodeBuilderRef& B, SVal location, SVal val) {}
+
+ // End-of-path and dead symbol notification.
+
+ virtual void EvalEndPath(GRExprEngine& Engine,
+ GREndPathNodeBuilder& Builder) {}
+
+
+ virtual void EvalDeadSymbols(ExplodedNodeSet& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder& Builder,
+ ExplodedNode* Pred,
+ Stmt* S, const GRState* state,
+ SymbolReaper& SymReaper) {}
+
+ // Return statements.
+ virtual void EvalReturn(ExplodedNodeSet& Dst,
+ GRExprEngine& Engine,
+ GRStmtNodeBuilder& Builder,
+ ReturnStmt* S,
+ ExplodedNode* Pred) {}
+
+ // Assumptions.
+ virtual const GRState* EvalAssume(const GRState *state,
+ SVal Cond, bool Assumption) {
+ return state;
+ }
+};
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/GRWorkList.h b/include/clang/Checker/PathSensitive/GRWorkList.h
new file mode 100644
index 0000000..b8f90fa
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/GRWorkList.h
@@ -0,0 +1,79 @@
+//==- GRWorkList.h - Worklist class used by GRCoreEngine -----------*- 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 GRWorkList, a pure virtual class that represents an opaque
+// worklist used by GRCoreEngine to explore the reachability state space.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_GRWORKLIST
+#define LLVM_CLANG_ANALYSIS_GRWORKLIST
+
+#include "clang/Checker/PathSensitive/GRBlockCounter.h"
+#include <cstddef>
+
+namespace clang {
+
+class CFGBlock;
+class ExplodedNode;
+class ExplodedNodeImpl;
+
+class GRWorkListUnit {
+ ExplodedNode* Node;
+ GRBlockCounter Counter;
+ CFGBlock* Block;
+ unsigned BlockIdx; // This is the index of the next statement.
+
+public:
+ GRWorkListUnit(ExplodedNode* N, GRBlockCounter C,
+ CFGBlock* B, unsigned idx)
+ : Node(N),
+ Counter(C),
+ Block(B),
+ BlockIdx(idx) {}
+
+ explicit GRWorkListUnit(ExplodedNode* N, GRBlockCounter C)
+ : Node(N),
+ Counter(C),
+ Block(NULL),
+ BlockIdx(0) {}
+
+ ExplodedNode* getNode() const { return Node; }
+ GRBlockCounter getBlockCounter() const { return Counter; }
+ CFGBlock* getBlock() const { return Block; }
+ unsigned getIndex() const { return BlockIdx; }
+};
+
+class GRWorkList {
+ GRBlockCounter CurrentCounter;
+public:
+ virtual ~GRWorkList();
+ virtual bool hasWork() const = 0;
+
+ virtual void Enqueue(const GRWorkListUnit& U) = 0;
+
+ void Enqueue(ExplodedNode* N, CFGBlock& B, unsigned idx) {
+ Enqueue(GRWorkListUnit(N, CurrentCounter, &B, idx));
+ }
+
+ void Enqueue(ExplodedNode* N) {
+ Enqueue(GRWorkListUnit(N, CurrentCounter));
+ }
+
+ virtual GRWorkListUnit Dequeue() = 0;
+
+ void setBlockCounter(GRBlockCounter C) { CurrentCounter = C; }
+ GRBlockCounter getBlockCounter() const { return CurrentCounter; }
+
+ static GRWorkList *MakeDFS();
+ static GRWorkList *MakeBFS();
+ static GRWorkList *MakeBFSBlockDFSContents();
+};
+} // end clang namespace
+#endif
diff --git a/include/clang/Checker/PathSensitive/MemRegion.h b/include/clang/Checker/PathSensitive/MemRegion.h
new file mode 100644
index 0000000..12bc0b7
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/MemRegion.h
@@ -0,0 +1,974 @@
+//== MemRegion.h - Abstract memory regions for static analysis --*- 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 MemRegion and its subclasses. MemRegion defines a
+// partially-typed abstraction of memory useful for path-sensitive dataflow
+// analyses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_MEMREGION_H
+#define LLVM_CLANG_ANALYSIS_MEMREGION_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/SVals.h"
+#include "clang/AST/ASTContext.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/Support/Allocator.h"
+#include <string>
+
+namespace llvm { class raw_ostream; }
+
+namespace clang {
+
+class MemRegionManager;
+class MemSpaceRegion;
+class LocationContext;
+class StackFrameContext;
+class VarRegion;
+
+//===----------------------------------------------------------------------===//
+// Base region classes.
+//===----------------------------------------------------------------------===//
+
+/// MemRegion - The root abstract class for all memory regions.
+class MemRegion : public llvm::FoldingSetNode {
+ friend class MemRegionManager;
+public:
+ enum Kind {
+ // Memory spaces.
+ BEG_MEMSPACES,
+ GenericMemSpaceRegionKind = BEG_MEMSPACES,
+ StackLocalsSpaceRegionKind,
+ StackArgumentsSpaceRegionKind,
+ HeapSpaceRegionKind,
+ UnknownSpaceRegionKind,
+ GlobalsSpaceRegionKind,
+ END_MEMSPACES = GlobalsSpaceRegionKind,
+ // Untyped regions.
+ SymbolicRegionKind,
+ AllocaRegionKind,
+ // Typed regions.
+ BEG_TYPED_REGIONS,
+ FunctionTextRegionKind = BEG_TYPED_REGIONS,
+ BlockTextRegionKind,
+ BlockDataRegionKind,
+ CompoundLiteralRegionKind,
+ CXXThisRegionKind,
+ StringRegionKind,
+ ElementRegionKind,
+ // Decl Regions.
+ BEG_DECL_REGIONS,
+ VarRegionKind = BEG_DECL_REGIONS,
+ FieldRegionKind,
+ ObjCIvarRegionKind,
+ CXXObjectRegionKind,
+ END_DECL_REGIONS = CXXObjectRegionKind,
+ END_TYPED_REGIONS = END_DECL_REGIONS
+ };
+
+private:
+ const Kind kind;
+
+protected:
+ MemRegion(Kind k) : kind(k) {}
+ virtual ~MemRegion();
+
+public:
+ ASTContext &getContext() const;
+
+ virtual void Profile(llvm::FoldingSetNodeID& ID) const = 0;
+
+ virtual MemRegionManager* getMemRegionManager() const = 0;
+
+ std::string getString() const;
+
+ const MemSpaceRegion *getMemorySpace() const;
+
+ const MemRegion *getBaseRegion() const;
+
+ const MemRegion *StripCasts() const;
+
+ bool hasGlobalsOrParametersStorage() const;
+
+ bool hasStackStorage() const;
+
+ bool hasStackNonParametersStorage() const;
+
+ bool hasStackParametersStorage() const;
+
+ virtual void dumpToStream(llvm::raw_ostream& os) const;
+
+ void dump() const;
+
+ Kind getKind() const { return kind; }
+
+ template<typename RegionTy> const RegionTy* getAs() const;
+
+ virtual bool isBoundable() const { return false; }
+
+ static bool classof(const MemRegion*) { return true; }
+};
+
+/// MemSpaceRegion - A memory region that represents and "memory space";
+/// for example, the set of global variables, the stack frame, etc.
+class MemSpaceRegion : public MemRegion {
+protected:
+ friend class MemRegionManager;
+
+ MemRegionManager *Mgr;
+
+ MemSpaceRegion(MemRegionManager *mgr, Kind k = GenericMemSpaceRegionKind)
+ : MemRegion(k), Mgr(mgr) {
+ assert(classof(this));
+ }
+
+ MemRegionManager* getMemRegionManager() const { return Mgr; }
+
+public:
+ bool isBoundable() const { return false; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ static bool classof(const MemRegion *R) {
+ Kind k = R->getKind();
+ return k >= BEG_MEMSPACES && k <= END_MEMSPACES;
+ }
+};
+
+class GlobalsSpaceRegion : public MemSpaceRegion {
+ friend class MemRegionManager;
+
+ GlobalsSpaceRegion(MemRegionManager *mgr)
+ : MemSpaceRegion(mgr, GlobalsSpaceRegionKind) {}
+public:
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == GlobalsSpaceRegionKind;
+ }
+};
+
+class HeapSpaceRegion : public MemSpaceRegion {
+ friend class MemRegionManager;
+
+ HeapSpaceRegion(MemRegionManager *mgr)
+ : MemSpaceRegion(mgr, HeapSpaceRegionKind) {}
+public:
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == HeapSpaceRegionKind;
+ }
+};
+
+class UnknownSpaceRegion : public MemSpaceRegion {
+ friend class MemRegionManager;
+ UnknownSpaceRegion(MemRegionManager *mgr)
+ : MemSpaceRegion(mgr, UnknownSpaceRegionKind) {}
+public:
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == UnknownSpaceRegionKind;
+ }
+};
+
+class StackSpaceRegion : public MemSpaceRegion {
+private:
+ const StackFrameContext *SFC;
+
+protected:
+ StackSpaceRegion(MemRegionManager *mgr, Kind k, const StackFrameContext *sfc)
+ : MemSpaceRegion(mgr, k), SFC(sfc) {
+ assert(classof(this));
+ }
+
+public:
+ const StackFrameContext *getStackFrame() const { return SFC; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ static bool classof(const MemRegion *R) {
+ Kind k = R->getKind();
+ return k >= StackLocalsSpaceRegionKind &&
+ k <= StackArgumentsSpaceRegionKind;
+ }
+};
+
+class StackLocalsSpaceRegion : public StackSpaceRegion {
+private:
+ friend class MemRegionManager;
+ StackLocalsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
+ : StackSpaceRegion(mgr, StackLocalsSpaceRegionKind, sfc) {}
+public:
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == StackLocalsSpaceRegionKind;
+ }
+};
+
+class StackArgumentsSpaceRegion : public StackSpaceRegion {
+private:
+ friend class MemRegionManager;
+ StackArgumentsSpaceRegion(MemRegionManager *mgr, const StackFrameContext *sfc)
+ : StackSpaceRegion(mgr, StackArgumentsSpaceRegionKind, sfc) {}
+public:
+ static bool classof(const MemRegion *R) {
+ return R->getKind() == StackArgumentsSpaceRegionKind;
+ }
+};
+
+/// SubRegion - A region that subsets another larger region. Most regions
+/// are subclasses of SubRegion.
+class SubRegion : public MemRegion {
+protected:
+ const MemRegion* superRegion;
+ SubRegion(const MemRegion* sReg, Kind k) : MemRegion(k), superRegion(sReg) {}
+public:
+ const MemRegion* getSuperRegion() const {
+ return superRegion;
+ }
+
+ MemRegionManager* getMemRegionManager() const;
+
+ bool isSubRegionOf(const MemRegion* R) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() > END_MEMSPACES;
+ }
+};
+
+//===----------------------------------------------------------------------===//
+// Auxillary data classes for use with MemRegions.
+//===----------------------------------------------------------------------===//
+
+class ElementRegion;
+
+class RegionRawOffset {
+private:
+ friend class ElementRegion;
+
+ const MemRegion *Region;
+ int64_t Offset;
+
+ RegionRawOffset(const MemRegion* reg, int64_t offset = 0)
+ : Region(reg), Offset(offset) {}
+
+public:
+ // FIXME: Eventually support symbolic offsets.
+ int64_t getByteOffset() const { return Offset; }
+ const MemRegion *getRegion() const { return Region; }
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+ void dump() const;
+};
+
+//===----------------------------------------------------------------------===//
+// MemRegion subclasses.
+//===----------------------------------------------------------------------===//
+
+/// AllocaRegion - A region that represents an untyped blob of bytes created
+/// by a call to 'alloca'.
+class AllocaRegion : public SubRegion {
+ friend class MemRegionManager;
+protected:
+ unsigned Cnt; // Block counter. Used to distinguish different pieces of
+ // memory allocated by alloca at the same call site.
+ const Expr* Ex;
+
+ AllocaRegion(const Expr* ex, unsigned cnt, const MemRegion *superRegion)
+ : SubRegion(superRegion, AllocaRegionKind), Cnt(cnt), Ex(ex) {}
+
+public:
+
+ const Expr* getExpr() const { return Ex; }
+
+ bool isBoundable() const { return true; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Expr* Ex,
+ unsigned Cnt, const MemRegion *superRegion);
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == AllocaRegionKind;
+ }
+};
+
+/// TypedRegion - An abstract class representing regions that are typed.
+class TypedRegion : public SubRegion {
+protected:
+ TypedRegion(const MemRegion* sReg, Kind k) : SubRegion(sReg, k) {}
+
+public:
+ virtual QualType getValueType(ASTContext &C) const = 0;
+
+ virtual QualType getLocationType(ASTContext& C) const {
+ // FIXME: We can possibly optimize this later to cache this value.
+ return C.getPointerType(getValueType(C));
+ }
+
+ QualType getDesugaredValueType(ASTContext& C) const {
+ QualType T = getValueType(C);
+ return T.getTypePtr() ? T.getDesugaredType() : T;
+ }
+
+ QualType getDesugaredLocationType(ASTContext& C) const {
+ return getLocationType(C).getDesugaredType();
+ }
+
+ bool isBoundable() const {
+ return !getValueType(getContext()).isNull();
+ }
+
+ static bool classof(const MemRegion* R) {
+ unsigned k = R->getKind();
+ return k >= BEG_TYPED_REGIONS && k <= END_TYPED_REGIONS;
+ }
+};
+
+
+class CodeTextRegion : public TypedRegion {
+protected:
+ CodeTextRegion(const MemRegion *sreg, Kind k) : TypedRegion(sreg, k) {}
+public:
+ QualType getValueType(ASTContext &C) const {
+ // Do not get the object type of a CodeTextRegion.
+ assert(0);
+ return QualType();
+ }
+
+ bool isBoundable() const { return false; }
+
+ static bool classof(const MemRegion* R) {
+ Kind k = R->getKind();
+ return k >= FunctionTextRegionKind && k <= BlockTextRegionKind;
+ }
+};
+
+/// FunctionTextRegion - A region that represents code texts of function.
+class FunctionTextRegion : public CodeTextRegion {
+ const FunctionDecl *FD;
+public:
+ FunctionTextRegion(const FunctionDecl* fd, const MemRegion* sreg)
+ : CodeTextRegion(sreg, FunctionTextRegionKind), FD(fd) {}
+
+ QualType getLocationType(ASTContext &C) const {
+ return C.getPointerType(FD->getType());
+ }
+
+ const FunctionDecl *getDecl() const {
+ return FD;
+ }
+
+ virtual void dumpToStream(llvm::raw_ostream& os) const;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FunctionDecl *FD,
+ const MemRegion*);
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == FunctionTextRegionKind;
+ }
+};
+
+
+/// BlockTextRegion - A region that represents code texts of blocks (closures).
+/// Blocks are represented with two kinds of regions. BlockTextRegions
+/// represent the "code", while BlockDataRegions represent instances of blocks,
+/// which correspond to "code+data". The distinction is important, because
+/// like a closure a block captures the values of externally referenced
+/// variables.
+class BlockTextRegion : public CodeTextRegion {
+ friend class MemRegionManager;
+
+ const BlockDecl *BD;
+ AnalysisContext *AC;
+ CanQualType locTy;
+
+ BlockTextRegion(const BlockDecl *bd, CanQualType lTy,
+ AnalysisContext *ac, const MemRegion* sreg)
+ : CodeTextRegion(sreg, BlockTextRegionKind), BD(bd), AC(ac), locTy(lTy) {}
+
+public:
+ QualType getLocationType(ASTContext &C) const {
+ return locTy;
+ }
+
+ const BlockDecl *getDecl() const {
+ return BD;
+ }
+
+ AnalysisContext *getAnalysisContext() const { return AC; }
+
+ virtual void dumpToStream(llvm::raw_ostream& os) const;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const BlockDecl *BD,
+ CanQualType, const AnalysisContext*,
+ const MemRegion*);
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == BlockTextRegionKind;
+ }
+};
+
+/// BlockDataRegion - A region that represents a block instance.
+/// Blocks are represented with two kinds of regions. BlockTextRegions
+/// represent the "code", while BlockDataRegions represent instances of blocks,
+/// which correspond to "code+data". The distinction is important, because
+/// like a closure a block captures the values of externally referenced
+/// variables.
+/// BlockDataRegion - A region that represents code texts of blocks (closures).
+class BlockDataRegion : public SubRegion {
+ friend class MemRegionManager;
+ const BlockTextRegion *BC;
+ const LocationContext *LC; // Can be null */
+ void *ReferencedVars;
+
+ BlockDataRegion(const BlockTextRegion *bc, const LocationContext *lc,
+ const MemRegion *sreg)
+ : SubRegion(sreg, BlockDataRegionKind), BC(bc), LC(lc), ReferencedVars(0) {}
+
+public:
+ const BlockTextRegion *getCodeRegion() const { return BC; }
+
+ const BlockDecl *getDecl() const { return BC->getDecl(); }
+
+ class referenced_vars_iterator {
+ const MemRegion * const *R;
+ public:
+ explicit referenced_vars_iterator(const MemRegion * const *r) : R(r) {}
+
+ operator const MemRegion * const *() const {
+ return R;
+ }
+
+ const VarRegion* operator*() const {
+ return cast<VarRegion>(*R);
+ }
+
+ bool operator==(const referenced_vars_iterator &I) const {
+ return I.R == R;
+ }
+ bool operator!=(const referenced_vars_iterator &I) const {
+ return I.R != R;
+ }
+ referenced_vars_iterator& operator++() {
+ ++R;
+ return *this;
+ }
+ };
+
+ referenced_vars_iterator referenced_vars_begin() const;
+ referenced_vars_iterator referenced_vars_end() const;
+
+ virtual void dumpToStream(llvm::raw_ostream& os) const;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static void ProfileRegion(llvm::FoldingSetNodeID&, const BlockTextRegion *,
+ const LocationContext *, const MemRegion *);
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == BlockDataRegionKind;
+ }
+private:
+ void LazyInitializeReferencedVars();
+};
+
+/// SymbolicRegion - A special, "non-concrete" region. Unlike other region
+/// clases, SymbolicRegion represents a region that serves as an alias for
+/// either a real region, a NULL pointer, etc. It essentially is used to
+/// map the concept of symbolic values into the domain of regions. Symbolic
+/// regions do not need to be typed.
+class SymbolicRegion : public SubRegion {
+protected:
+ const SymbolRef sym;
+
+public:
+ SymbolicRegion(const SymbolRef s, const MemRegion* sreg)
+ : SubRegion(sreg, SymbolicRegionKind), sym(s) {}
+
+ SymbolRef getSymbol() const {
+ return sym;
+ }
+
+ bool isBoundable() const { return true; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+ SymbolRef sym,
+ const MemRegion* superRegion);
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == SymbolicRegionKind;
+ }
+};
+
+/// StringRegion - Region associated with a StringLiteral.
+class StringRegion : public TypedRegion {
+ friend class MemRegionManager;
+ const StringLiteral* Str;
+protected:
+
+ StringRegion(const StringLiteral* str, const MemRegion* sreg)
+ : TypedRegion(sreg, StringRegionKind), Str(str) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const StringLiteral* Str,
+ const MemRegion* superRegion);
+
+public:
+
+ const StringLiteral* getStringLiteral() const { return Str; }
+
+ QualType getValueType(ASTContext& C) const {
+ return Str->getType();
+ }
+
+ bool isBoundable() const { return false; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ProfileRegion(ID, Str, superRegion);
+ }
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == StringRegionKind;
+ }
+};
+
+/// CompoundLiteralRegion - A memory region representing a compound literal.
+/// Compound literals are essentially temporaries that are stack allocated
+/// or in the global constant pool.
+class CompoundLiteralRegion : public TypedRegion {
+private:
+ friend class MemRegionManager;
+ const CompoundLiteralExpr* CL;
+
+ CompoundLiteralRegion(const CompoundLiteralExpr* cl, const MemRegion* sReg)
+ : TypedRegion(sReg, CompoundLiteralRegionKind), CL(cl) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID,
+ const CompoundLiteralExpr* CL,
+ const MemRegion* superRegion);
+public:
+ QualType getValueType(ASTContext& C) const {
+ return C.getCanonicalType(CL->getType());
+ }
+
+ bool isBoundable() const { return !CL->isFileScope(); }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ const CompoundLiteralExpr* getLiteralExpr() const { return CL; }
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == CompoundLiteralRegionKind;
+ }
+};
+
+class DeclRegion : public TypedRegion {
+protected:
+ const Decl* D;
+
+ DeclRegion(const Decl* d, const MemRegion* sReg, Kind k)
+ : TypedRegion(sReg, k), D(d) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const Decl* D,
+ const MemRegion* superRegion, Kind k);
+
+public:
+ const Decl* getDecl() const { return D; }
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static bool classof(const MemRegion* R) {
+ unsigned k = R->getKind();
+ return k >= BEG_DECL_REGIONS && k <= END_DECL_REGIONS;
+ }
+};
+
+class VarRegion : public DeclRegion {
+ friend class MemRegionManager;
+
+ // Constructors and private methods.
+ VarRegion(const VarDecl* vd, const MemRegion* sReg)
+ : DeclRegion(vd, sReg, VarRegionKind) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const VarDecl* VD,
+ const MemRegion *superRegion) {
+ DeclRegion::ProfileRegion(ID, VD, superRegion, VarRegionKind);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+public:
+ const VarDecl *getDecl() const { return cast<VarDecl>(D); }
+
+ const StackFrameContext *getStackFrame() const;
+
+ QualType getValueType(ASTContext& C) const {
+ // FIXME: We can cache this if needed.
+ return C.getCanonicalType(getDecl()->getType());
+ }
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == VarRegionKind;
+ }
+};
+
+/// CXXThisRegion - Represents the region for the implicit 'this' parameter
+/// in a call to a C++ method. This region doesn't represent the object
+/// referred to by 'this', but rather 'this' itself.
+class CXXThisRegion : public TypedRegion {
+ friend class MemRegionManager;
+ CXXThisRegion(const PointerType *thisPointerTy,
+ const MemRegion *sReg)
+ : TypedRegion(sReg, CXXThisRegionKind), ThisPointerTy(thisPointerTy) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+ const PointerType *PT,
+ const MemRegion *sReg);
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+public:
+ QualType getValueType(ASTContext &C) const {
+ return QualType(ThisPointerTy, 0);
+ }
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == CXXThisRegionKind;
+ }
+
+private:
+ const PointerType *ThisPointerTy;
+};
+
+class FieldRegion : public DeclRegion {
+ friend class MemRegionManager;
+
+ FieldRegion(const FieldDecl* fd, const MemRegion* sReg)
+ : DeclRegion(fd, sReg, FieldRegionKind) {}
+
+public:
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ const FieldDecl* getDecl() const { return cast<FieldDecl>(D); }
+
+ QualType getValueType(ASTContext& C) const {
+ // FIXME: We can cache this if needed.
+ return C.getCanonicalType(getDecl()->getType());
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const FieldDecl* FD,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, FD, superRegion, FieldRegionKind);
+ }
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == FieldRegionKind;
+ }
+};
+
+class ObjCIvarRegion : public DeclRegion {
+
+ friend class MemRegionManager;
+
+ ObjCIvarRegion(const ObjCIvarDecl* ivd, const MemRegion* sReg)
+ : DeclRegion(ivd, sReg, ObjCIvarRegionKind) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, const ObjCIvarDecl* ivd,
+ const MemRegion* superRegion) {
+ DeclRegion::ProfileRegion(ID, ivd, superRegion, ObjCIvarRegionKind);
+ }
+
+public:
+ const ObjCIvarDecl* getDecl() const { return cast<ObjCIvarDecl>(D); }
+ QualType getValueType(ASTContext&) const { return getDecl()->getType(); }
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == ObjCIvarRegionKind;
+ }
+};
+
+class ElementRegion : public TypedRegion {
+ friend class MemRegionManager;
+
+ QualType ElementType;
+ SVal Index;
+
+ ElementRegion(QualType elementType, SVal Idx, const MemRegion* sReg)
+ : TypedRegion(sReg, ElementRegionKind),
+ ElementType(elementType), Index(Idx) {
+ assert((!isa<nonloc::ConcreteInt>(&Idx) ||
+ cast<nonloc::ConcreteInt>(&Idx)->getValue().isSigned()) &&
+ "The index must be signed");
+ }
+
+ static void ProfileRegion(llvm::FoldingSetNodeID& ID, QualType elementType,
+ SVal Idx, const MemRegion* superRegion);
+
+public:
+
+ SVal getIndex() const { return Index; }
+
+ QualType getValueType(ASTContext&) const {
+ return ElementType;
+ }
+
+ QualType getElementType() const {
+ return ElementType;
+ }
+
+ RegionRawOffset getAsRawOffset() const;
+
+ void dumpToStream(llvm::raw_ostream& os) const;
+
+ void Profile(llvm::FoldingSetNodeID& ID) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == ElementRegionKind;
+ }
+};
+
+// C++ temporary object associated with an expression.
+class CXXObjectRegion : public TypedRegion {
+ friend class MemRegionManager;
+
+ Expr const *Ex;
+
+ CXXObjectRegion(Expr const *E, MemRegion const *sReg)
+ : TypedRegion(sReg, CXXObjectRegionKind), Ex(E) {}
+
+ static void ProfileRegion(llvm::FoldingSetNodeID &ID,
+ Expr const *E, const MemRegion *sReg);
+
+public:
+ QualType getValueType(ASTContext& C) const {
+ return Ex->getType();
+ }
+
+ void Profile(llvm::FoldingSetNodeID &ID) const;
+
+ static bool classof(const MemRegion* R) {
+ return R->getKind() == CXXObjectRegionKind;
+ }
+};
+
+template<typename RegionTy>
+const RegionTy* MemRegion::getAs() const {
+ if (const RegionTy* RT = dyn_cast<RegionTy>(this))
+ return RT;
+
+ return NULL;
+}
+
+//===----------------------------------------------------------------------===//
+// MemRegionManager - Factory object for creating regions.
+//===----------------------------------------------------------------------===//
+
+class MemRegionManager {
+ ASTContext &C;
+ llvm::BumpPtrAllocator& A;
+ llvm::FoldingSet<MemRegion> Regions;
+
+ GlobalsSpaceRegion *globals;
+
+ const StackFrameContext *cachedStackLocalsFrame;
+ StackLocalsSpaceRegion *cachedStackLocalsRegion;
+
+ const StackFrameContext *cachedStackArgumentsFrame;
+ StackArgumentsSpaceRegion *cachedStackArgumentsRegion;
+
+ HeapSpaceRegion *heap;
+ UnknownSpaceRegion *unknown;
+ MemSpaceRegion *code;
+
+public:
+ MemRegionManager(ASTContext &c, llvm::BumpPtrAllocator& a)
+ : C(c), A(a), globals(0),
+ cachedStackLocalsFrame(0), cachedStackLocalsRegion(0),
+ cachedStackArgumentsFrame(0), cachedStackArgumentsRegion(0),
+ heap(0), unknown(0), code(0) {}
+
+ ~MemRegionManager();
+
+ ASTContext &getContext() { return C; }
+
+ llvm::BumpPtrAllocator &getAllocator() { return A; }
+
+ /// getStackLocalsRegion - Retrieve the memory region associated with the
+ /// specified stack frame.
+ const StackLocalsSpaceRegion *
+ getStackLocalsRegion(const StackFrameContext *STC);
+
+ /// getStackArgumentsRegion - Retrieve the memory region associated with
+ /// function/method arguments of the specified stack frame.
+ const StackArgumentsSpaceRegion *
+ getStackArgumentsRegion(const StackFrameContext *STC);
+
+ /// getGlobalsRegion - Retrieve the memory region associated with
+ /// all global variables.
+ const GlobalsSpaceRegion *getGlobalsRegion();
+
+ /// getHeapRegion - Retrieve the memory region associated with the
+ /// generic "heap".
+ const HeapSpaceRegion *getHeapRegion();
+
+ /// getUnknownRegion - Retrieve the memory region associated with unknown
+ /// memory space.
+ const MemSpaceRegion *getUnknownRegion();
+
+ const MemSpaceRegion *getCodeRegion();
+
+ /// getAllocaRegion - Retrieve a region associated with a call to alloca().
+ const AllocaRegion *getAllocaRegion(const Expr* Ex, unsigned Cnt,
+ const LocationContext *LC);
+
+ /// getCompoundLiteralRegion - Retrieve the region associated with a
+ /// given CompoundLiteral.
+ const CompoundLiteralRegion*
+ getCompoundLiteralRegion(const CompoundLiteralExpr* CL,
+ const LocationContext *LC);
+
+ /// getCXXThisRegion - Retrieve the [artifical] region associated with the
+ /// parameter 'this'.
+ const CXXThisRegion *getCXXThisRegion(QualType thisPointerTy,
+ const LocationContext *LC);
+
+ /// getSymbolicRegion - Retrieve or create a "symbolic" memory region.
+ const SymbolicRegion* getSymbolicRegion(SymbolRef sym);
+
+ const StringRegion* getStringRegion(const StringLiteral* Str);
+
+ /// getVarRegion - Retrieve or create the memory region associated with
+ /// a specified VarDecl and LocationContext.
+ const VarRegion* getVarRegion(const VarDecl *D, const LocationContext *LC);
+
+ /// getVarRegion - Retrieve or create the memory region associated with
+ /// a specified VarDecl and super region.
+ const VarRegion* getVarRegion(const VarDecl *D, const MemRegion *superR);
+
+ /// getElementRegion - Retrieve the memory region associated with the
+ /// associated element type, index, and super region.
+ const ElementRegion *getElementRegion(QualType elementType, SVal Idx,
+ const MemRegion *superRegion,
+ ASTContext &Ctx);
+
+ const ElementRegion *getElementRegionWithSuper(const ElementRegion *ER,
+ const MemRegion *superRegion) {
+ return getElementRegion(ER->getElementType(), ER->getIndex(),
+ superRegion, ER->getContext());
+ }
+
+ /// getFieldRegion - Retrieve or create the memory region associated with
+ /// a specified FieldDecl. 'superRegion' corresponds to the containing
+ /// memory region (which typically represents the memory representing
+ /// a structure or class).
+ const FieldRegion *getFieldRegion(const FieldDecl* fd,
+ const MemRegion* superRegion);
+
+ const FieldRegion *getFieldRegionWithSuper(const FieldRegion *FR,
+ const MemRegion *superRegion) {
+ return getFieldRegion(FR->getDecl(), superRegion);
+ }
+
+ /// getObjCIvarRegion - Retrieve or create the memory region associated with
+ /// a specified Objective-c instance variable. 'superRegion' corresponds
+ /// to the containing region (which typically represents the Objective-C
+ /// object).
+ const ObjCIvarRegion *getObjCIvarRegion(const ObjCIvarDecl* ivd,
+ const MemRegion* superRegion);
+
+ const CXXObjectRegion *getCXXObjectRegion(Expr const *Ex,
+ LocationContext const *LC);
+
+ const FunctionTextRegion *getFunctionTextRegion(const FunctionDecl *FD);
+ const BlockTextRegion *getBlockTextRegion(const BlockDecl *BD,
+ CanQualType locTy,
+ AnalysisContext *AC);
+
+ /// getBlockDataRegion - Get the memory region associated with an instance
+ /// of a block. Unlike many other MemRegions, the LocationContext*
+ /// argument is allowed to be NULL for cases where we have no known
+ /// context.
+ const BlockDataRegion *getBlockDataRegion(const BlockTextRegion *bc,
+ const LocationContext *lc = NULL);
+
+ bool isGlobalsRegion(const MemRegion* R) {
+ assert(R);
+ return R == globals;
+ }
+
+private:
+ template <typename RegionTy, typename A1>
+ RegionTy* getRegion(const A1 a1);
+
+ template <typename RegionTy, typename A1>
+ RegionTy* getSubRegion(const A1 a1, const MemRegion* superRegion);
+
+ template <typename RegionTy, typename A1, typename A2>
+ RegionTy* getRegion(const A1 a1, const A2 a2);
+
+ template <typename RegionTy, typename A1, typename A2>
+ RegionTy* getSubRegion(const A1 a1, const A2 a2,
+ const MemRegion* superRegion);
+
+ template <typename RegionTy, typename A1, typename A2, typename A3>
+ RegionTy* getSubRegion(const A1 a1, const A2 a2, const A3 a3,
+ const MemRegion* superRegion);
+
+ template <typename REG>
+ const REG* LazyAllocate(REG*& region);
+
+ template <typename REG, typename ARG>
+ const REG* LazyAllocate(REG*& region, ARG a);
+};
+
+//===----------------------------------------------------------------------===//
+// Out-of-line member definitions.
+//===----------------------------------------------------------------------===//
+
+inline ASTContext& MemRegion::getContext() const {
+ return getMemRegionManager()->getContext();
+}
+
+} // end clang namespace
+
+//===----------------------------------------------------------------------===//
+// Pretty-printing regions.
+//===----------------------------------------------------------------------===//
+
+namespace llvm {
+static inline raw_ostream& operator<<(raw_ostream& os,
+ const clang::MemRegion* R) {
+ R->dumpToStream(os);
+ return os;
+}
+} // end llvm namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/SVals.h b/include/clang/Checker/PathSensitive/SVals.h
new file mode 100644
index 0000000..65a8a2c
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/SVals.h
@@ -0,0 +1,499 @@
+//== SVals.h - Abstract Values for Static Analysis ---------*- 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 SVal, Loc, and NonLoc, classes that represent
+// abstract r-values for use with path-sensitive value tracking.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_RVALUE_H
+#define LLVM_CLANG_ANALYSIS_RVALUE_H
+
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/ADT/ImmutableList.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+//==------------------------------------------------------------------------==//
+// Base SVal types.
+//==------------------------------------------------------------------------==//
+
+namespace clang {
+
+class CompoundValData;
+class LazyCompoundValData;
+class GRState;
+class BasicValueFactory;
+class MemRegion;
+class TypedRegion;
+class MemRegionManager;
+class GRStateManager;
+class ValueManager;
+
+class SVal {
+public:
+ enum BaseKind { UndefinedKind, UnknownKind, LocKind, NonLocKind };
+ enum { BaseBits = 2, BaseMask = 0x3 };
+
+protected:
+ void* Data;
+ unsigned Kind;
+
+protected:
+ SVal(const void* d, bool isLoc, unsigned ValKind)
+ : Data(const_cast<void*>(d)),
+ Kind((isLoc ? LocKind : NonLocKind) | (ValKind << BaseBits)) {}
+
+ explicit SVal(BaseKind k, void* D = NULL)
+ : Data(D), Kind(k) {}
+
+public:
+ SVal() : Data(0), Kind(0) {}
+ ~SVal() {}
+
+ /// BufferTy - A temporary buffer to hold a set of SVals.
+ typedef llvm::SmallVector<SVal,5> BufferTy;
+
+ inline unsigned getRawKind() const { return Kind; }
+ inline BaseKind getBaseKind() const { return (BaseKind) (Kind & BaseMask); }
+ inline unsigned getSubKind() const { return (Kind & ~BaseMask) >> BaseBits; }
+
+ inline void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddInteger((unsigned) getRawKind());
+ ID.AddPointer(reinterpret_cast<void*>(Data));
+ }
+
+ inline bool operator==(const SVal& R) const {
+ return getRawKind() == R.getRawKind() && Data == R.Data;
+ }
+
+ inline bool operator!=(const SVal& R) const {
+ return !(*this == R);
+ }
+
+ inline bool isUnknown() const {
+ return getRawKind() == UnknownKind;
+ }
+
+ inline bool isUndef() const {
+ return getRawKind() == UndefinedKind;
+ }
+
+ inline bool isUnknownOrUndef() const {
+ return getRawKind() <= UnknownKind;
+ }
+
+ inline bool isValid() const {
+ return getRawKind() > UnknownKind;
+ }
+
+ bool isConstant() const;
+
+ bool isZeroConstant() const;
+
+ /// hasConjuredSymbol - If this SVal wraps a conjured symbol, return true;
+ bool hasConjuredSymbol() const;
+
+ /// getAsFunctionDecl - If this SVal is a MemRegionVal and wraps a
+ /// CodeTextRegion wrapping a FunctionDecl, return that FunctionDecl.
+ /// Otherwise return 0.
+ const FunctionDecl* getAsFunctionDecl() const;
+
+ /// getAsLocSymbol - If this SVal is a location (subclasses Loc) and
+ /// wraps a symbol, return that SymbolRef. Otherwise return a SymbolData*
+ SymbolRef getAsLocSymbol() const;
+
+ /// getAsSymbol - If this Sval wraps a symbol return that SymbolRef.
+ /// Otherwise return a SymbolRef where 'isValid()' returns false.
+ SymbolRef getAsSymbol() const;
+
+ /// getAsSymbolicExpression - If this Sval wraps a symbolic expression then
+ /// return that expression. Otherwise return NULL.
+ const SymExpr *getAsSymbolicExpression() const;
+
+ const MemRegion *getAsRegion() const;
+
+ void dumpToStream(llvm::raw_ostream& OS) const;
+ void dump() const;
+
+ // Iterators.
+ class symbol_iterator {
+ llvm::SmallVector<const SymExpr*, 5> itr;
+ void expand();
+ public:
+ symbol_iterator() {}
+ symbol_iterator(const SymExpr* SE);
+
+ symbol_iterator& operator++();
+ SymbolRef operator*();
+
+ bool operator==(const symbol_iterator& X) const;
+ bool operator!=(const symbol_iterator& X) const;
+ };
+
+ symbol_iterator symbol_begin() const {
+ const SymExpr *SE = getAsSymbolicExpression();
+ if (SE)
+ return symbol_iterator(SE);
+ else
+ return symbol_iterator();
+ }
+
+ symbol_iterator symbol_end() const { return symbol_iterator(); }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal*) { return true; }
+};
+
+
+class UndefinedVal : public SVal {
+public:
+ UndefinedVal() : SVal(UndefinedKind) {}
+ UndefinedVal(void* D) : SVal(UndefinedKind, D) {}
+
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == UndefinedKind;
+ }
+
+ void* getData() const { return Data; }
+};
+
+class DefinedOrUnknownSVal : public SVal {
+private:
+ // Do not implement. We want calling these methods to be a compiler
+ // error since they are tautologically false.
+ bool isUndef() const;
+ bool isValid() const;
+
+protected:
+ explicit DefinedOrUnknownSVal(const void* d, bool isLoc, unsigned ValKind)
+ : SVal(d, isLoc, ValKind) {}
+
+ explicit DefinedOrUnknownSVal(BaseKind k, void *D = NULL)
+ : SVal(k, D) {}
+
+public:
+ // Implement isa<T> support.
+ static inline bool classof(const SVal *V) {
+ return !V->isUndef();
+ }
+};
+
+class UnknownVal : public DefinedOrUnknownSVal {
+public:
+ UnknownVal() : DefinedOrUnknownSVal(UnknownKind) {}
+
+ static inline bool classof(const SVal *V) {
+ return V->getBaseKind() == UnknownKind;
+ }
+};
+
+class DefinedSVal : public DefinedOrUnknownSVal {
+private:
+ // Do not implement. We want calling these methods to be a compiler
+ // error since they are tautologically true/false.
+ bool isUnknown() const;
+ bool isUnknownOrUndef() const;
+ bool isValid() const;
+protected:
+ DefinedSVal(const void* d, bool isLoc, unsigned ValKind)
+ : DefinedOrUnknownSVal(d, isLoc, ValKind) {}
+public:
+ // Implement isa<T> support.
+ static inline bool classof(const SVal *V) {
+ return !V->isUnknownOrUndef();
+ }
+};
+
+class NonLoc : public DefinedSVal {
+protected:
+ NonLoc(unsigned SubKind, const void* d) : DefinedSVal(d, false, SubKind) {}
+
+public:
+ void dumpToStream(llvm::raw_ostream& Out) const;
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind;
+ }
+};
+
+class Loc : public DefinedSVal {
+protected:
+ Loc(unsigned SubKind, const void* D)
+ : DefinedSVal(const_cast<void*>(D), true, SubKind) {}
+
+public:
+ void dumpToStream(llvm::raw_ostream& Out) const;
+
+ Loc(const Loc& X) : DefinedSVal(X.Data, true, X.getSubKind()) {}
+ Loc& operator=(const Loc& X) { memcpy(this, &X, sizeof(Loc)); return *this; }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == LocKind;
+ }
+
+ static inline bool IsLocType(QualType T) {
+ return T->isAnyPointerType() || T->isBlockPointerType() ||
+ T->isReferenceType();
+ }
+};
+
+//==------------------------------------------------------------------------==//
+// Subclasses of NonLoc.
+//==------------------------------------------------------------------------==//
+
+namespace nonloc {
+
+enum Kind { ConcreteIntKind, SymbolValKind, SymExprValKind,
+ LocAsIntegerKind, CompoundValKind, LazyCompoundValKind };
+
+class SymbolVal : public NonLoc {
+public:
+ SymbolVal(SymbolRef sym) : NonLoc(SymbolValKind, sym) {}
+
+ SymbolRef getSymbol() const {
+ return (const SymbolData*) Data;
+ }
+
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == SymbolValKind;
+ }
+
+ static inline bool classof(const NonLoc* V) {
+ return V->getSubKind() == SymbolValKind;
+ }
+};
+
+class SymExprVal : public NonLoc {
+public:
+ SymExprVal(const SymExpr *SE)
+ : NonLoc(SymExprValKind, reinterpret_cast<const void*>(SE)) {}
+
+ const SymExpr *getSymbolicExpression() const {
+ return reinterpret_cast<SymExpr*>(Data);
+ }
+
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == SymExprValKind;
+ }
+
+ static inline bool classof(const NonLoc* V) {
+ return V->getSubKind() == SymExprValKind;
+ }
+};
+
+class ConcreteInt : public NonLoc {
+public:
+ ConcreteInt(const llvm::APSInt& V) : NonLoc(ConcreteIntKind, &V) {}
+
+ const llvm::APSInt& getValue() const {
+ return *static_cast<llvm::APSInt*>(Data);
+ }
+
+ // Transfer functions for binary/unary operations on ConcreteInts.
+ SVal evalBinOp(ValueManager &ValMgr, BinaryOperator::Opcode Op,
+ const ConcreteInt& R) const;
+
+ ConcreteInt evalComplement(ValueManager &ValMgr) const;
+
+ ConcreteInt evalMinus(ValueManager &ValMgr) const;
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == ConcreteIntKind;
+ }
+
+ static inline bool classof(const NonLoc* V) {
+ return V->getSubKind() == ConcreteIntKind;
+ }
+};
+
+class LocAsInteger : public NonLoc {
+ friend class clang::ValueManager;
+
+ LocAsInteger(const std::pair<SVal, uintptr_t>& data) :
+ NonLoc(LocAsIntegerKind, &data) {
+ assert (isa<Loc>(data.first));
+ }
+
+public:
+
+ Loc getLoc() const {
+ return cast<Loc>(((std::pair<SVal, uintptr_t>*) Data)->first);
+ }
+
+ const Loc& getPersistentLoc() const {
+ const SVal& V = ((std::pair<SVal, uintptr_t>*) Data)->first;
+ return cast<Loc>(V);
+ }
+
+ unsigned getNumBits() const {
+ return ((std::pair<SVal, unsigned>*) Data)->second;
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == LocAsIntegerKind;
+ }
+
+ static inline bool classof(const NonLoc* V) {
+ return V->getSubKind() == LocAsIntegerKind;
+ }
+};
+
+class CompoundVal : public NonLoc {
+ friend class clang::ValueManager;
+
+ CompoundVal(const CompoundValData* D) : NonLoc(CompoundValKind, D) {}
+
+public:
+ const CompoundValData* getValue() const {
+ return static_cast<CompoundValData*>(Data);
+ }
+
+ typedef llvm::ImmutableList<SVal>::iterator iterator;
+ iterator begin() const;
+ iterator end() const;
+
+ static bool classof(const SVal* V) {
+ return V->getBaseKind() == NonLocKind && V->getSubKind() == CompoundValKind;
+ }
+
+ static bool classof(const NonLoc* V) {
+ return V->getSubKind() == CompoundValKind;
+ }
+};
+
+class LazyCompoundVal : public NonLoc {
+ friend class clang::ValueManager;
+
+ LazyCompoundVal(const LazyCompoundValData *D)
+ : NonLoc(LazyCompoundValKind, D) {}
+public:
+ const LazyCompoundValData *getCVData() const {
+ return static_cast<const LazyCompoundValData*>(Data);
+ }
+ const void *getStore() const;
+ const TypedRegion *getRegion() const;
+
+ static bool classof(const SVal *V) {
+ return V->getBaseKind() == NonLocKind &&
+ V->getSubKind() == LazyCompoundValKind;
+ }
+ static bool classof(const NonLoc *V) {
+ return V->getSubKind() == LazyCompoundValKind;
+ }
+};
+
+} // end namespace clang::nonloc
+
+//==------------------------------------------------------------------------==//
+// Subclasses of Loc.
+//==------------------------------------------------------------------------==//
+
+namespace loc {
+
+enum Kind { GotoLabelKind, MemRegionKind, ConcreteIntKind };
+
+class GotoLabel : public Loc {
+public:
+ GotoLabel(LabelStmt* Label) : Loc(GotoLabelKind, Label) {}
+
+ LabelStmt* getLabel() const {
+ return static_cast<LabelStmt*>(Data);
+ }
+
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == LocKind &&
+ V->getSubKind() == GotoLabelKind;
+ }
+
+ static inline bool classof(const Loc* V) {
+ return V->getSubKind() == GotoLabelKind;
+ }
+};
+
+
+class MemRegionVal : public Loc {
+public:
+ MemRegionVal(const MemRegion* r) : Loc(MemRegionKind, r) {}
+
+ const MemRegion* getRegion() const {
+ return static_cast<MemRegion*>(Data);
+ }
+
+ const MemRegion* StripCasts() const;
+
+ template <typename REGION>
+ const REGION* getRegionAs() const {
+ return llvm::dyn_cast<REGION>(getRegion());
+ }
+
+ inline bool operator==(const MemRegionVal& R) const {
+ return getRegion() == R.getRegion();
+ }
+
+ inline bool operator!=(const MemRegionVal& R) const {
+ return getRegion() != R.getRegion();
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == LocKind &&
+ V->getSubKind() == MemRegionKind;
+ }
+
+ static inline bool classof(const Loc* V) {
+ return V->getSubKind() == MemRegionKind;
+ }
+};
+
+class ConcreteInt : public Loc {
+public:
+ ConcreteInt(const llvm::APSInt& V) : Loc(ConcreteIntKind, &V) {}
+
+ const llvm::APSInt& getValue() const {
+ return *static_cast<llvm::APSInt*>(Data);
+ }
+
+ // Transfer functions for binary/unary operations on ConcreteInts.
+ SVal EvalBinOp(BasicValueFactory& BasicVals, BinaryOperator::Opcode Op,
+ const ConcreteInt& R) const;
+
+ // Implement isa<T> support.
+ static inline bool classof(const SVal* V) {
+ return V->getBaseKind() == LocKind &&
+ V->getSubKind() == ConcreteIntKind;
+ }
+
+ static inline bool classof(const Loc* V) {
+ return V->getSubKind() == ConcreteIntKind;
+ }
+};
+
+} // end clang::loc namespace
+} // end clang namespace
+
+namespace llvm {
+static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+ clang::SVal V) {
+ V.dumpToStream(os);
+ return os;
+}
+} // end llvm namespace
+#endif
diff --git a/include/clang/Checker/PathSensitive/SValuator.h b/include/clang/Checker/PathSensitive/SValuator.h
new file mode 100644
index 0000000..9beb8cb
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/SValuator.h
@@ -0,0 +1,66 @@
+// SValuator.h - Construction of SVals from evaluating expressions -*- 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 SValuator, a class that defines the interface for
+// "symbolical evaluators" which construct an SVal from an expression.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_SVALUATOR
+#define LLVM_CLANG_ANALYSIS_SVALUATOR
+
+#include "clang/AST/Expr.h"
+#include "clang/Checker/PathSensitive/SVals.h"
+
+namespace clang {
+
+class GRState;
+class ValueManager;
+
+class SValuator {
+ friend class ValueManager;
+protected:
+ ValueManager &ValMgr;
+
+public:
+ // FIXME: Make these protected again one RegionStoreManager correctly
+ // handles loads from differening bound value types.
+ virtual SVal EvalCastNL(NonLoc val, QualType castTy) = 0;
+ virtual SVal EvalCastL(Loc val, QualType castTy) = 0;
+
+public:
+ SValuator(ValueManager &valMgr) : ValMgr(valMgr) {}
+ virtual ~SValuator() {}
+
+ SVal EvalCast(SVal V, QualType castTy, QualType originalType);
+
+ virtual SVal EvalMinus(NonLoc val) = 0;
+
+ virtual SVal EvalComplement(NonLoc val) = 0;
+
+ virtual SVal EvalBinOpNN(const GRState *state, BinaryOperator::Opcode Op,
+ NonLoc lhs, NonLoc rhs, QualType resultTy) = 0;
+
+ virtual SVal EvalBinOpLL(BinaryOperator::Opcode Op, Loc lhs, Loc rhs,
+ QualType resultTy) = 0;
+
+ virtual SVal EvalBinOpLN(const GRState *state, BinaryOperator::Opcode Op,
+ Loc lhs, NonLoc rhs, QualType resultTy) = 0;
+
+ SVal EvalBinOp(const GRState *ST, BinaryOperator::Opcode Op,
+ SVal L, SVal R, QualType T);
+
+ DefinedOrUnknownSVal EvalEQ(const GRState *ST, DefinedOrUnknownSVal L,
+ DefinedOrUnknownSVal R);
+};
+
+SValuator* CreateSimpleSValuator(ValueManager &valMgr);
+
+} // end clang namespace
+#endif
diff --git a/include/clang/Checker/PathSensitive/Store.h b/include/clang/Checker/PathSensitive/Store.h
new file mode 100644
index 0000000..c660e7b
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/Store.h
@@ -0,0 +1,230 @@
+//== Store.h - Interface for maps from Locations to Values ------*- C++ -*--==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defined the types Store and StoreManager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_STORE_H
+#define LLVM_CLANG_ANALYSIS_STORE_H
+
+#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Checker/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/ValueManager.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallVector.h"
+
+namespace clang {
+
+typedef const void* Store;
+
+class GRState;
+class GRStateManager;
+class Stmt;
+class Expr;
+class ObjCIvarDecl;
+class SubRegionMap;
+class StackFrameContext;
+
+class StoreManager {
+protected:
+ ValueManager &ValMgr;
+ GRStateManager &StateMgr;
+
+ /// MRMgr - Manages region objects associated with this StoreManager.
+ MemRegionManager &MRMgr;
+ ASTContext &Ctx;
+
+ StoreManager(GRStateManager &stateMgr);
+
+public:
+ virtual ~StoreManager() {}
+
+ /// Return the value bound to specified location in a given state.
+ /// \param[in] state The analysis state.
+ /// \param[in] loc The symbolic memory location.
+ /// \param[in] T An optional type that provides a hint indicating the
+ /// expected type of the returned value. This is used if the value is
+ /// lazily computed.
+ /// \return The value bound to the location \c loc.
+ virtual SVal Retrieve(Store store, Loc loc, QualType T = QualType()) = 0;
+
+ /// Return a state with the specified value bound to the given location.
+ /// \param[in] state The analysis state.
+ /// \param[in] loc The symbolic memory location.
+ /// \param[in] val The value to bind to location \c loc.
+ /// \return A pointer to a GRState object that contains the same bindings as
+ /// \c state with the addition of having the value specified by \c val bound
+ /// to the location given for \c loc.
+ virtual Store Bind(Store store, Loc loc, SVal val) = 0;
+
+ virtual Store Remove(Store St, Loc L) = 0;
+
+ /// BindCompoundLiteral - Return the store that has the bindings currently
+ /// in 'store' plus the bindings for the CompoundLiteral. 'R' is the region
+ /// for the compound literal and 'BegInit' and 'EndInit' represent an
+ /// array of initializer values.
+ virtual Store BindCompoundLiteral(Store store,
+ const CompoundLiteralExpr* cl,
+ const LocationContext *LC, SVal v) = 0;
+
+ /// getInitialStore - Returns the initial "empty" store representing the
+ /// value bindings upon entry to an analyzed function.
+ virtual Store getInitialStore(const LocationContext *InitLoc) = 0;
+
+ /// getRegionManager - Returns the internal RegionManager object that is
+ /// used to query and manipulate MemRegion objects.
+ MemRegionManager& getRegionManager() { return MRMgr; }
+
+ /// getSubRegionMap - Returns an opaque map object that clients can query
+ /// to get the subregions of a given MemRegion object. It is the
+ // caller's responsibility to 'delete' the returned map.
+ virtual SubRegionMap *getSubRegionMap(Store store) = 0;
+
+ virtual SVal getLValueVar(const VarDecl *VD, const LocationContext *LC) {
+ return ValMgr.makeLoc(MRMgr.getVarRegion(VD, LC));
+ }
+
+ virtual SVal getLValueString(const StringLiteral* S) {
+ return ValMgr.makeLoc(MRMgr.getStringRegion(S));
+ }
+
+ SVal getLValueCompoundLiteral(const CompoundLiteralExpr* CL,
+ const LocationContext *LC) {
+ return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC));
+ }
+
+ virtual SVal getLValueIvar(const ObjCIvarDecl* decl, SVal base) {
+ return getLValueFieldOrIvar(decl, base);
+ }
+
+ virtual SVal getLValueField(const FieldDecl* D, SVal Base) {
+ return getLValueFieldOrIvar(D, Base);
+ }
+
+ virtual SVal getLValueElement(QualType elementType, SVal offset, SVal Base);
+
+ // FIXME: Make out-of-line.
+ virtual DefinedOrUnknownSVal getSizeInElements(const GRState *state,
+ const MemRegion *region,
+ QualType EleTy) {
+ return UnknownVal();
+ }
+
+ /// ArrayToPointer - Used by GRExprEngine::VistCast to handle implicit
+ /// conversions between arrays and pointers.
+ virtual SVal ArrayToPointer(Loc Array) = 0;
+
+ class CastResult {
+ const GRState *state;
+ const MemRegion *region;
+ public:
+ const GRState *getState() const { return state; }
+ const MemRegion* getRegion() const { return region; }
+ CastResult(const GRState *s, const MemRegion* r = 0) : state(s), region(r){}
+ };
+
+ /// CastRegion - Used by GRExprEngine::VisitCast to handle casts from
+ /// a MemRegion* to a specific location type. 'R' is the region being
+ /// casted and 'CastToTy' the result type of the cast.
+ const MemRegion *CastRegion(const MemRegion *region, QualType CastToTy);
+
+ /// EvalBinOp - Perform pointer arithmetic.
+ virtual SVal EvalBinOp(BinaryOperator::Opcode Op,
+ Loc lhs, NonLoc rhs, QualType resultTy) {
+ return UnknownVal();
+ }
+
+ virtual Store RemoveDeadBindings(Store store, Stmt* Loc,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots) = 0;
+
+ virtual Store BindDecl(Store store, const VarRegion *VR, SVal initVal) = 0;
+
+ virtual Store BindDeclWithNoInit(Store store, const VarRegion *VR) = 0;
+
+ typedef llvm::DenseSet<SymbolRef> InvalidatedSymbols;
+
+ virtual Store InvalidateRegion(Store store,
+ const MemRegion *R,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS) = 0;
+
+ virtual Store InvalidateRegions(Store store,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS);
+
+ // FIXME: Make out-of-line.
+ virtual const GRState *setExtent(const GRState *state,
+ const MemRegion *region, SVal extent) {
+ return state;
+ }
+
+ /// EnterStackFrame - Let the StoreManager to do something when execution
+ /// engine is about to execute into a callee.
+ virtual const GRState *EnterStackFrame(const GRState *state,
+ const StackFrameContext *frame) {
+ return state;
+ }
+
+ virtual void print(Store store, llvm::raw_ostream& Out,
+ const char* nl, const char *sep) = 0;
+
+ class BindingsHandler {
+ public:
+ virtual ~BindingsHandler();
+ virtual bool HandleBinding(StoreManager& SMgr, Store store,
+ const MemRegion *region, SVal val) = 0;
+ };
+
+ /// iterBindings - Iterate over the bindings in the Store.
+ virtual void iterBindings(Store store, BindingsHandler& f) = 0;
+
+protected:
+ const MemRegion *MakeElementRegion(const MemRegion *Base,
+ QualType pointeeTy, uint64_t index = 0);
+
+ /// CastRetrievedVal - Used by subclasses of StoreManager to implement
+ /// implicit casts that arise from loads from regions that are reinterpreted
+ /// as another region.
+ SVal CastRetrievedVal(SVal val, const TypedRegion *R, QualType castTy,
+ bool performTestOnly = true);
+
+private:
+ SVal getLValueFieldOrIvar(const Decl* D, SVal Base);
+};
+
+// FIXME: Do we still need this?
+/// SubRegionMap - An abstract interface that represents a queryable map
+/// between MemRegion objects and their subregions.
+class SubRegionMap {
+public:
+ virtual ~SubRegionMap() {}
+
+ class Visitor {
+ public:
+ virtual ~Visitor() {}
+ virtual bool Visit(const MemRegion* Parent, const MemRegion* SubRegion) = 0;
+ };
+
+ virtual bool iterSubRegions(const MemRegion *region, Visitor& V) const = 0;
+};
+
+// FIXME: Do we need to pass GRStateManager anymore?
+StoreManager *CreateBasicStoreManager(GRStateManager& StMgr);
+StoreManager *CreateRegionStoreManager(GRStateManager& StMgr);
+StoreManager *CreateFieldsOnlyRegionStoreManager(GRStateManager& StMgr);
+StoreManager *CreateFlatStoreManager(GRStateManager &StMgr);
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/SummaryManager.h b/include/clang/Checker/PathSensitive/SummaryManager.h
new file mode 100644
index 0000000..fd23189
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/SummaryManager.h
@@ -0,0 +1,57 @@
+//== SummaryManager.h - Generic handling of function summaries --*- 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 SummaryManager and related classes, which provides
+// a generic mechanism for managing function summaries.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_CHECKER_SUMMARY
+#define LLVM_CLANG_CHECKER_SUMMARY
+
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/Support/Allocator.h"
+
+namespace clang {
+
+namespace summMgr {
+
+
+/* Key kinds:
+
+ - C functions
+ - C++ functions (name + parameter types)
+ - ObjC methods:
+ - Class, selector (class method)
+ - Class, selector (instance method)
+ - Category, selector (instance method)
+ - Protocol, selector (instance method)
+ - C++ methods
+ - Class, function name + parameter types + const
+ */
+
+class SummaryKey {
+
+};
+
+} // end namespace clang::summMgr
+
+class SummaryManagerImpl {
+
+};
+
+
+template <typename T>
+class SummaryManager : SummaryManagerImpl {
+
+};
+
+} // end clang namespace
+
+#endif
diff --git a/include/clang/Checker/PathSensitive/SymbolManager.h b/include/clang/Checker/PathSensitive/SymbolManager.h
new file mode 100644
index 0000000..8eb3196
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/SymbolManager.h
@@ -0,0 +1,385 @@
+//== SymbolManager.h - Management of Symbolic Values ------------*- 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 SymbolManager, a class that manages symbolic values
+// created for use by GRExprEngine and related classes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_SYMMGR_H
+#define LLVM_CLANG_ANALYSIS_SYMMGR_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "llvm/System/DataTypes.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/ADT/FoldingSet.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace llvm {
+ class raw_ostream;
+}
+
+namespace clang {
+ class ASTContext;
+ class BasicValueFactory;
+ class MemRegion;
+ class TypedRegion;
+ class VarRegion;
+ class StackFrameContext;
+}
+
+namespace clang {
+
+class SymExpr : public llvm::FoldingSetNode {
+public:
+ enum Kind { BEGIN_SYMBOLS,
+ RegionValueKind, ConjuredKind, DerivedKind,
+ END_SYMBOLS,
+ SymIntKind, SymSymKind };
+private:
+ Kind K;
+
+protected:
+ SymExpr(Kind k) : K(k) {}
+
+public:
+ virtual ~SymExpr() {}
+
+ Kind getKind() const { return K; }
+
+ void dump() const;
+
+ virtual void dumpToStream(llvm::raw_ostream &os) const = 0;
+
+ virtual QualType getType(ASTContext&) const = 0;
+ virtual void Profile(llvm::FoldingSetNodeID& profile) = 0;
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr*) { return true; }
+};
+
+typedef unsigned SymbolID;
+
+class SymbolData : public SymExpr {
+private:
+ const SymbolID Sym;
+
+protected:
+ SymbolData(Kind k, SymbolID sym) : SymExpr(k), Sym(sym) {}
+
+public:
+ virtual ~SymbolData() {}
+
+ SymbolID getSymbolID() const { return Sym; }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ Kind k = SE->getKind();
+ return k > BEGIN_SYMBOLS && k < END_SYMBOLS;
+ }
+};
+
+typedef const SymbolData* SymbolRef;
+
+class SymbolRegionValue : public SymbolData {
+ const MemRegion *R;
+ // We may cast the region to another type, so the expected type of the symbol
+ // may be different from the region's original type.
+ QualType T;
+
+public:
+ SymbolRegionValue(SymbolID sym, const MemRegion *r, QualType t = QualType())
+ : SymbolData(RegionValueKind, sym), R(r), T(t) {}
+
+ const MemRegion* getRegion() const { return R; }
+
+ static void Profile(llvm::FoldingSetNodeID& profile, const MemRegion* R,
+ QualType T) {
+ profile.AddInteger((unsigned) RegionValueKind);
+ profile.AddPointer(R);
+ T.Profile(profile);
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID& profile) {
+ Profile(profile, R, T);
+ }
+
+ void dumpToStream(llvm::raw_ostream &os) const;
+
+ QualType getType(ASTContext&) const;
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == RegionValueKind;
+ }
+};
+
+class SymbolConjured : public SymbolData {
+ const Stmt* S;
+ QualType T;
+ unsigned Count;
+ const void* SymbolTag;
+
+public:
+ SymbolConjured(SymbolID sym, const Stmt* s, QualType t, unsigned count,
+ const void* symbolTag)
+ : SymbolData(ConjuredKind, sym), S(s), T(t), Count(count),
+ SymbolTag(symbolTag) {}
+
+ const Stmt* getStmt() const { return S; }
+ unsigned getCount() const { return Count; }
+ const void* getTag() const { return SymbolTag; }
+
+ QualType getType(ASTContext&) const;
+
+ void dumpToStream(llvm::raw_ostream &os) const;
+
+ static void Profile(llvm::FoldingSetNodeID& profile, const Stmt* S,
+ QualType T, unsigned Count, const void* SymbolTag) {
+ profile.AddInteger((unsigned) ConjuredKind);
+ profile.AddPointer(S);
+ profile.Add(T);
+ profile.AddInteger(Count);
+ profile.AddPointer(SymbolTag);
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID& profile) {
+ Profile(profile, S, T, Count, SymbolTag);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == ConjuredKind;
+ }
+};
+
+class SymbolDerived : public SymbolData {
+ SymbolRef parentSymbol;
+ const TypedRegion *R;
+
+public:
+ SymbolDerived(SymbolID sym, SymbolRef parent, const TypedRegion *r)
+ : SymbolData(DerivedKind, sym), parentSymbol(parent), R(r) {}
+
+ SymbolRef getParentSymbol() const { return parentSymbol; }
+ const TypedRegion *getRegion() const { return R; }
+
+ QualType getType(ASTContext&) const;
+
+ void dumpToStream(llvm::raw_ostream &os) const;
+
+ static void Profile(llvm::FoldingSetNodeID& profile, SymbolRef parent,
+ const TypedRegion *r) {
+ profile.AddInteger((unsigned) DerivedKind);
+ profile.AddPointer(r);
+ profile.AddPointer(parent);
+ }
+
+ virtual void Profile(llvm::FoldingSetNodeID& profile) {
+ Profile(profile, parentSymbol, R);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == DerivedKind;
+ }
+};
+
+// SymIntExpr - Represents symbolic expression like 'x' + 3.
+class SymIntExpr : public SymExpr {
+ const SymExpr *LHS;
+ BinaryOperator::Opcode Op;
+ const llvm::APSInt& RHS;
+ QualType T;
+
+public:
+ SymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType t)
+ : SymExpr(SymIntKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
+
+ // FIXME: We probably need to make this out-of-line to avoid redundant
+ // generation of virtual functions.
+ QualType getType(ASTContext& C) const { return T; }
+
+ BinaryOperator::Opcode getOpcode() const { return Op; }
+
+ void dumpToStream(llvm::raw_ostream &os) const;
+
+ const SymExpr *getLHS() const { return LHS; }
+ const llvm::APSInt &getRHS() const { return RHS; }
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
+ BinaryOperator::Opcode op, const llvm::APSInt& rhs,
+ QualType t) {
+ ID.AddInteger((unsigned) SymIntKind);
+ ID.AddPointer(lhs);
+ ID.AddInteger(op);
+ ID.AddPointer(&rhs);
+ ID.Add(t);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) {
+ Profile(ID, LHS, Op, RHS, T);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == SymIntKind;
+ }
+};
+
+// SymSymExpr - Represents symbolic expression like 'x' + 'y'.
+class SymSymExpr : public SymExpr {
+ const SymExpr *LHS;
+ BinaryOperator::Opcode Op;
+ const SymExpr *RHS;
+ QualType T;
+
+public:
+ SymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op, const SymExpr *rhs,
+ QualType t)
+ : SymExpr(SymSymKind), LHS(lhs), Op(op), RHS(rhs), T(t) {}
+
+ const SymExpr *getLHS() const { return LHS; }
+ const SymExpr *getRHS() const { return RHS; }
+
+ // FIXME: We probably need to make this out-of-line to avoid redundant
+ // generation of virtual functions.
+ QualType getType(ASTContext& C) const { return T; }
+
+ void dumpToStream(llvm::raw_ostream &os) const;
+
+ static void Profile(llvm::FoldingSetNodeID& ID, const SymExpr *lhs,
+ BinaryOperator::Opcode op, const SymExpr *rhs, QualType t) {
+ ID.AddInteger((unsigned) SymSymKind);
+ ID.AddPointer(lhs);
+ ID.AddInteger(op);
+ ID.AddPointer(rhs);
+ ID.Add(t);
+ }
+
+ void Profile(llvm::FoldingSetNodeID& ID) {
+ Profile(ID, LHS, Op, RHS, T);
+ }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymExpr* SE) {
+ return SE->getKind() == SymSymKind;
+ }
+};
+
+class SymbolManager {
+ typedef llvm::FoldingSet<SymExpr> DataSetTy;
+ DataSetTy DataSet;
+ unsigned SymbolCounter;
+ llvm::BumpPtrAllocator& BPAlloc;
+ BasicValueFactory &BV;
+ ASTContext& Ctx;
+
+public:
+ SymbolManager(ASTContext& ctx, BasicValueFactory &bv,
+ llvm::BumpPtrAllocator& bpalloc)
+ : SymbolCounter(0), BPAlloc(bpalloc), BV(bv), Ctx(ctx) {}
+
+ ~SymbolManager();
+
+ static bool canSymbolicate(QualType T);
+
+ /// Make a unique symbol for MemRegion R according to its kind.
+ const SymbolRegionValue* getRegionValueSymbol(const MemRegion* R,
+ QualType T = QualType());
+ const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
+ unsigned VisitCount,
+ const void* SymbolTag = 0);
+
+ const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
+ const void* SymbolTag = 0) {
+ return getConjuredSymbol(E, E->getType(), VisitCount, SymbolTag);
+ }
+
+ const SymbolDerived *getDerivedSymbol(SymbolRef parentSymbol,
+ const TypedRegion *R);
+
+ const SymIntExpr *getSymIntExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType t);
+
+ const SymIntExpr *getSymIntExpr(const SymExpr &lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType t) {
+ return getSymIntExpr(&lhs, op, rhs, t);
+ }
+
+ const SymSymExpr *getSymSymExpr(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType t);
+
+ QualType getType(const SymExpr *SE) const {
+ return SE->getType(Ctx);
+ }
+
+ ASTContext &getContext() { return Ctx; }
+ BasicValueFactory &getBasicVals() { return BV; }
+};
+
+class SymbolReaper {
+ typedef llvm::DenseSet<SymbolRef> SetTy;
+
+ SetTy TheLiving;
+ SetTy TheDead;
+ LiveVariables& Liveness;
+ SymbolManager& SymMgr;
+ const StackFrameContext *CurrentStackFrame;
+
+public:
+ SymbolReaper(LiveVariables& liveness, SymbolManager& symmgr,
+ const StackFrameContext *currentStackFrame)
+ : Liveness(liveness), SymMgr(symmgr), CurrentStackFrame(currentStackFrame)
+ {}
+
+ ~SymbolReaper() {}
+
+ bool isLive(SymbolRef sym);
+
+ bool isLive(const Stmt* Loc, const Stmt* ExprVal) const {
+ return Liveness.isLive(Loc, ExprVal);
+ }
+
+ bool isLive(const Stmt* Loc, const VarRegion *VR) const;
+
+ void markLive(SymbolRef sym);
+ bool maybeDead(SymbolRef sym);
+
+ typedef SetTy::const_iterator dead_iterator;
+ dead_iterator dead_begin() const { return TheDead.begin(); }
+ dead_iterator dead_end() const { return TheDead.end(); }
+
+ bool hasDeadSymbols() const {
+ return !TheDead.empty();
+ }
+};
+
+class SymbolVisitor {
+public:
+ // VisitSymbol - A visitor method invoked by
+ // GRStateManager::scanReachableSymbols. The method returns \c true if
+ // symbols should continue be scanned and \c false otherwise.
+ virtual bool VisitSymbol(SymbolRef sym) = 0;
+ virtual ~SymbolVisitor();
+};
+
+} // end clang namespace
+
+namespace llvm {
+static inline llvm::raw_ostream& operator<<(llvm::raw_ostream& os,
+ const clang::SymExpr *SE) {
+ SE->dumpToStream(os);
+ return os;
+}
+} // end llvm namespace
+#endif
diff --git a/include/clang/Checker/PathSensitive/ValueManager.h b/include/clang/Checker/PathSensitive/ValueManager.h
new file mode 100644
index 0000000..ea3af57
--- /dev/null
+++ b/include/clang/Checker/PathSensitive/ValueManager.h
@@ -0,0 +1,208 @@
+//== ValueManager.h - Aggregate manager of symbols and SVals ----*- 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 ValueManager, a class that manages symbolic values
+// and SVals created for use by GRExprEngine and related classes. It
+// wraps and owns SymbolManager, MemRegionManager, and BasicValueFactory.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H
+#define LLVM_CLANG_ANALYSIS_AGGREGATE_VALUE_MANAGER_H
+
+#include "llvm/ADT/OwningPtr.h"
+#include "clang/Checker/PathSensitive/MemRegion.h"
+#include "clang/Checker/PathSensitive/SVals.h"
+#include "clang/Checker/PathSensitive/BasicValueFactory.h"
+#include "clang/Checker/PathSensitive/SymbolManager.h"
+#include "clang/Checker/PathSensitive/SValuator.h"
+
+namespace llvm { class BumpPtrAllocator; }
+
+namespace clang {
+
+class GRStateManager;
+
+class ValueManager {
+
+ ASTContext &Context;
+ BasicValueFactory BasicVals;
+
+ /// SymMgr - Object that manages the symbol information.
+ SymbolManager SymMgr;
+
+ /// SVator - SValuator object that creates SVals from expressions.
+ llvm::OwningPtr<SValuator> SVator;
+
+ MemRegionManager MemMgr;
+
+ GRStateManager &StateMgr;
+
+ const QualType ArrayIndexTy;
+ const unsigned ArrayIndexWidth;
+
+public:
+ ValueManager(llvm::BumpPtrAllocator &alloc, ASTContext &context,
+ GRStateManager &stateMgr)
+ : Context(context), BasicVals(context, alloc),
+ SymMgr(context, BasicVals, alloc),
+ MemMgr(context, alloc), StateMgr(stateMgr),
+ ArrayIndexTy(context.IntTy),
+ ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {
+ // FIXME: Generalize later.
+ SVator.reset(clang::CreateSimpleSValuator(*this));
+ }
+
+ // Accessors to submanagers.
+
+ ASTContext &getContext() { return Context; }
+ const ASTContext &getContext() const { return Context; }
+
+ GRStateManager &getStateManager() { return StateMgr; }
+
+ BasicValueFactory &getBasicValueFactory() { return BasicVals; }
+ const BasicValueFactory &getBasicValueFactory() const { return BasicVals; }
+
+ SymbolManager &getSymbolManager() { return SymMgr; }
+ const SymbolManager &getSymbolManager() const { return SymMgr; }
+
+ SValuator &getSValuator() { return *SVator.get(); }
+
+ MemRegionManager &getRegionManager() { return MemMgr; }
+ const MemRegionManager &getRegionManager() const { return MemMgr; }
+
+ // Forwarding methods to SymbolManager.
+
+ const SymbolConjured* getConjuredSymbol(const Stmt* E, QualType T,
+ unsigned VisitCount,
+ const void* SymbolTag = 0) {
+ return SymMgr.getConjuredSymbol(E, T, VisitCount, SymbolTag);
+ }
+
+ const SymbolConjured* getConjuredSymbol(const Expr* E, unsigned VisitCount,
+ const void* SymbolTag = 0) {
+ return SymMgr.getConjuredSymbol(E, VisitCount, SymbolTag);
+ }
+
+ /// makeZeroVal - Construct an SVal representing '0' for the specified type.
+ DefinedOrUnknownSVal makeZeroVal(QualType T);
+
+ /// getRegionValueSymbolVal - make a unique symbol for value of R.
+ DefinedOrUnknownSVal getRegionValueSymbolVal(const MemRegion *R,
+ QualType T = QualType());
+
+ DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
+ const Expr *E, unsigned Count);
+ DefinedOrUnknownSVal getConjuredSymbolVal(const void *SymbolTag,
+ const Expr *E, QualType T,
+ unsigned Count);
+
+ DefinedOrUnknownSVal getDerivedRegionValueSymbolVal(SymbolRef parentSymbol,
+ const TypedRegion *R);
+
+ DefinedSVal getFunctionPointer(const FunctionDecl *FD);
+
+ DefinedSVal getBlockPointer(const BlockDecl *BD, CanQualType locTy,
+ const LocationContext *LC);
+
+ NonLoc makeCompoundVal(QualType T, llvm::ImmutableList<SVal> Vals) {
+ return nonloc::CompoundVal(BasicVals.getCompoundValData(T, Vals));
+ }
+
+ NonLoc makeLazyCompoundVal(const void *store, const TypedRegion *R) {
+ return nonloc::LazyCompoundVal(BasicVals.getLazyCompoundValData(store, R));
+ }
+
+ NonLoc makeZeroArrayIndex() {
+ return nonloc::ConcreteInt(BasicVals.getValue(0, ArrayIndexTy));
+ }
+
+ NonLoc makeArrayIndex(uint64_t idx) {
+ return nonloc::ConcreteInt(BasicVals.getValue(idx, ArrayIndexTy));
+ }
+
+ SVal convertToArrayIndex(SVal V);
+
+ nonloc::ConcreteInt makeIntVal(const IntegerLiteral* I) {
+ return nonloc::ConcreteInt(BasicVals.getValue(I->getValue(),
+ I->getType()->isUnsignedIntegerType()));
+ }
+
+ nonloc::ConcreteInt makeIntVal(const llvm::APSInt& V) {
+ return nonloc::ConcreteInt(BasicVals.getValue(V));
+ }
+
+ loc::ConcreteInt makeIntLocVal(const llvm::APSInt &v) {
+ return loc::ConcreteInt(BasicVals.getValue(v));
+ }
+
+ NonLoc makeIntVal(const llvm::APInt& V, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getValue(V, isUnsigned));
+ }
+
+ DefinedSVal makeIntVal(uint64_t X, QualType T) {
+ if (Loc::IsLocType(T))
+ return loc::ConcreteInt(BasicVals.getValue(X, T));
+
+ return nonloc::ConcreteInt(BasicVals.getValue(X, T));
+ }
+
+ NonLoc makeIntVal(uint64_t X, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getIntValue(X, isUnsigned));
+ }
+
+ NonLoc makeIntValWithPtrWidth(uint64_t X, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getIntWithPtrWidth(X, isUnsigned));
+ }
+
+ NonLoc makeIntVal(uint64_t X, unsigned BitWidth, bool isUnsigned) {
+ return nonloc::ConcreteInt(BasicVals.getValue(X, BitWidth, isUnsigned));
+ }
+
+ NonLoc makeLocAsInteger(Loc V, unsigned Bits) {
+ return nonloc::LocAsInteger(BasicVals.getPersistentSValWithData(V, Bits));
+ }
+
+ NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const llvm::APSInt& rhs, QualType T);
+
+ NonLoc makeNonLoc(const SymExpr *lhs, BinaryOperator::Opcode op,
+ const SymExpr *rhs, QualType T);
+
+ NonLoc makeTruthVal(bool b, QualType T) {
+ return nonloc::ConcreteInt(BasicVals.getTruthValue(b, T));
+ }
+
+ NonLoc makeTruthVal(bool b) {
+ return nonloc::ConcreteInt(BasicVals.getTruthValue(b));
+ }
+
+ Loc makeNull() {
+ return loc::ConcreteInt(BasicVals.getZeroWithPtrWidth());
+ }
+
+ Loc makeLoc(SymbolRef Sym) {
+ return loc::MemRegionVal(MemMgr.getSymbolicRegion(Sym));
+ }
+
+ Loc makeLoc(const MemRegion* R) {
+ return loc::MemRegionVal(R);
+ }
+
+ Loc makeLoc(const AddrLabelExpr* E) {
+ return loc::GotoLabel(E->getLabel());
+ }
+
+ Loc makeLoc(const llvm::APSInt& V) {
+ return loc::ConcreteInt(BasicVals.getValue(V));
+ }
+};
+} // end clang namespace
+#endif
+
OpenPOWER on IntegriCloud