aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-02-08 22:30:36 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2011-02-08 22:30:36 +0000
commit811d75ee35b8b061a9b10a4e7b81e0c0eaf739c3 (patch)
tree76064238268b854e8698c225b3eb44eefedd6559 /lib/StaticAnalyzer/Core
parenta12a51701794a5ce96d47513ed186922e41eadd5 (diff)
[analyzer] Move the files in lib/StaticAnalyzer to lib/StaticAnalyzer/Core.
Eventually there will also be a lib/StaticAnalyzer/Frontend that will handle initialization and checker registration. Yet another library to avoid cyclic dependencies between Core and Checkers. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125124 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r--lib/StaticAnalyzer/Core/AggExprVisitor.cpp63
-rw-r--r--lib/StaticAnalyzer/Core/AnalysisManager.cpp32
-rw-r--r--lib/StaticAnalyzer/Core/BasicConstraintManager.cpp338
-rw-r--r--lib/StaticAnalyzer/Core/BasicStore.cpp594
-rw-r--r--lib/StaticAnalyzer/Core/BasicValueFactory.cpp290
-rw-r--r--lib/StaticAnalyzer/Core/BlockCounter.cpp86
-rw-r--r--lib/StaticAnalyzer/Core/BugReporter.cpp1892
-rw-r--r--lib/StaticAnalyzer/Core/BugReporterVisitors.cpp457
-rw-r--r--lib/StaticAnalyzer/Core/CFRefCount.cpp3525
-rw-r--r--lib/StaticAnalyzer/Core/CMakeLists.txt41
-rw-r--r--lib/StaticAnalyzer/Core/CXXExprEngine.cpp322
-rw-r--r--lib/StaticAnalyzer/Core/Checker.cpp35
-rw-r--r--lib/StaticAnalyzer/Core/CheckerHelpers.cpp80
-rw-r--r--lib/StaticAnalyzer/Core/CoreEngine.cpp844
-rw-r--r--lib/StaticAnalyzer/Core/Environment.cpp236
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp282
-rw-r--r--lib/StaticAnalyzer/Core/FlatStore.cpp203
-rw-r--r--lib/StaticAnalyzer/Core/GRState.cpp571
-rw-r--r--lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp581
-rw-r--r--lib/StaticAnalyzer/Core/Makefile17
-rw-r--r--lib/StaticAnalyzer/Core/ManagerRegistry.cpp21
-rw-r--r--lib/StaticAnalyzer/Core/MemRegion.cpp988
-rw-r--r--lib/StaticAnalyzer/Core/ObjCMessage.cpp99
-rw-r--r--lib/StaticAnalyzer/Core/PathDiagnostic.cpp279
-rw-r--r--lib/StaticAnalyzer/Core/PlistDiagnostics.cpp472
-rw-r--r--lib/StaticAnalyzer/Core/RangeConstraintManager.cpp442
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp1917
-rw-r--r--lib/StaticAnalyzer/Core/SValBuilder.cpp310
-rw-r--r--lib/StaticAnalyzer/Core/SVals.cpp378
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp303
-rw-r--r--lib/StaticAnalyzer/Core/SimpleConstraintManager.h93
-rw-r--r--lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp917
-rw-r--r--lib/StaticAnalyzer/Core/Store.cpp334
-rw-r--r--lib/StaticAnalyzer/Core/SymbolManager.cpp345
-rw-r--r--lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp70
35 files changed, 17457 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
new file mode 100644
index 0000000000..0cc23900ed
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp
@@ -0,0 +1,63 @@
+//=-- AggExprVisitor.cpp - evaluating expressions of C++ class type -*- 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 AggExprVisitor class, which contains lots of boiler
+// plate code for evaluating expressions of C++ class type.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
+#include "clang/AST/StmtVisitor.h"
+
+using namespace clang;
+using namespace ento;
+
+namespace {
+/// AggExprVisitor is designed after AggExprEmitter of the CodeGen module. It
+/// is used for evaluating exprs of C++ object type. Evaluating such exprs
+/// requires a destination pointer pointing to the object being evaluated
+/// into. Passing such a pointer around would pollute the Visit* interface of
+/// ExprEngine. AggExprVisitor encapsulates code that goes through various
+/// cast and construct exprs (and others), and at the final point, dispatches
+/// back to the ExprEngine to let the real evaluation logic happen.
+class AggExprVisitor : public StmtVisitor<AggExprVisitor> {
+ const MemRegion *Dest;
+ ExplodedNode *Pred;
+ ExplodedNodeSet &DstSet;
+ ExprEngine &Eng;
+
+public:
+ AggExprVisitor(const MemRegion *dest, ExplodedNode *N, ExplodedNodeSet &dst,
+ ExprEngine &eng)
+ : Dest(dest), Pred(N), DstSet(dst), Eng(eng) {}
+
+ void VisitCastExpr(CastExpr *E);
+ void VisitCXXConstructExpr(CXXConstructExpr *E);
+};
+}
+
+void AggExprVisitor::VisitCastExpr(CastExpr *E) {
+ switch (E->getCastKind()) {
+ default:
+ assert(0 && "Unhandled cast kind");
+ case CK_NoOp:
+ case CK_ConstructorConversion:
+ Visit(E->getSubExpr());
+ break;
+ }
+}
+
+void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) {
+ Eng.VisitCXXConstructExpr(E, Dest, Pred, DstSet);
+}
+
+void ExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest,
+ ExplodedNode *Pred, ExplodedNodeSet &Dst) {
+ AggExprVisitor(Dest, Pred, Dst, *this).Visit(const_cast<Expr *>(E));
+}
diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
new file mode 100644
index 0000000000..cc5e271393
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -0,0 +1,32 @@
+//===-- AnalysisManager.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
+#include "clang/Index/Entity.h"
+#include "clang/Index/Indexer.h"
+
+using namespace clang;
+using namespace ento;
+
+AnalysisContext *
+AnalysisManager::getAnalysisContextInAnotherTU(const Decl *D) {
+ idx::Entity Ent = idx::Entity::get(const_cast<Decl *>(D),
+ Idxer->getProgram());
+ FunctionDecl *FuncDef;
+ idx::TranslationUnit *TU;
+ llvm::tie(FuncDef, TU) = Idxer->getDefinitionFor(Ent);
+
+ if (FuncDef == 0)
+ return 0;
+
+ // This AnalysisContext wraps function definition in another translation unit.
+ // But it is still owned by the AnalysisManager associated with the current
+ // translation unit.
+ return AnaCtxMgr.getContext(FuncDef, TU);
+}
diff --git a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
new file mode 100644
index 0000000000..bbffa1a2fb
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp
@@ -0,0 +1,338 @@
+//== BasicConstraintManager.cpp - Manage basic constraints.------*- 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 BasicConstraintManager, a class that tracks simple
+// equality and inequality constraints on symbolic values of GRState.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SimpleConstraintManager.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+
+
+namespace { class ConstNotEq {}; }
+namespace { class ConstEq {}; }
+
+typedef llvm::ImmutableMap<SymbolRef,GRState::IntSetTy> ConstNotEqTy;
+typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy;
+
+static int ConstEqIndex = 0;
+static int ConstNotEqIndex = 0;
+
+namespace clang {
+namespace ento {
+template<>
+struct GRStateTrait<ConstNotEq> : public GRStatePartialTrait<ConstNotEqTy> {
+ static inline void* GDMIndex() { return &ConstNotEqIndex; }
+};
+
+template<>
+struct GRStateTrait<ConstEq> : public GRStatePartialTrait<ConstEqTy> {
+ static inline void* GDMIndex() { return &ConstEqIndex; }
+};
+}
+}
+
+namespace {
+// BasicConstraintManager only tracks equality and inequality constraints of
+// constants and integer variables.
+class BasicConstraintManager
+ : public SimpleConstraintManager {
+ GRState::IntSetTy::Factory ISetFactory;
+public:
+ BasicConstraintManager(GRStateManager &statemgr, SubEngine &subengine)
+ : SimpleConstraintManager(subengine),
+ ISetFactory(statemgr.getAllocator()) {}
+
+ const GRState *assumeSymNE(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const GRState *assumeSymEQ(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const GRState *assumeSymLT(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const GRState *assumeSymGT(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const GRState *assumeSymGE(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const GRState *assumeSymLE(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V,
+ const llvm::APSInt& Adjustment);
+
+ const GRState* AddEQ(const GRState* state, SymbolRef sym, const llvm::APSInt& V);
+
+ const GRState* AddNE(const GRState* state, SymbolRef sym, const llvm::APSInt& V);
+
+ const llvm::APSInt* getSymVal(const GRState* state, SymbolRef sym) const;
+ bool isNotEqual(const GRState* state, SymbolRef sym, const llvm::APSInt& V)
+ const;
+ bool isEqual(const GRState* state, SymbolRef sym, const llvm::APSInt& V)
+ const;
+
+ const GRState* removeDeadBindings(const GRState* state, SymbolReaper& SymReaper);
+
+ void print(const GRState* state, llvm::raw_ostream& Out,
+ const char* nl, const char *sep);
+};
+
+} // end anonymous namespace
+
+ConstraintManager* ento::CreateBasicConstraintManager(GRStateManager& statemgr,
+ SubEngine &subengine) {
+ return new BasicConstraintManager(statemgr, subengine);
+}
+
+
+const GRState*
+BasicConstraintManager::assumeSymNE(const GRState *state, SymbolRef sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) {
+ // First, determine if sym == X, where X+Adjustment != V.
+ llvm::APSInt Adjusted = V-Adjustment;
+ if (const llvm::APSInt* X = getSymVal(state, sym)) {
+ bool isFeasible = (*X != Adjusted);
+ return isFeasible ? state : NULL;
+ }
+
+ // Second, determine if sym+Adjustment != V.
+ if (isNotEqual(state, sym, Adjusted))
+ return state;
+
+ // If we reach here, sym is not a constant and we don't know if it is != V.
+ // Make that assumption.
+ return AddNE(state, sym, Adjusted);
+}
+
+const GRState*
+BasicConstraintManager::assumeSymEQ(const GRState *state, SymbolRef sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) {
+ // First, determine if sym == X, where X+Adjustment != V.
+ llvm::APSInt Adjusted = V-Adjustment;
+ if (const llvm::APSInt* X = getSymVal(state, sym)) {
+ bool isFeasible = (*X == Adjusted);
+ return isFeasible ? state : NULL;
+ }
+
+ // Second, determine if sym+Adjustment != V.
+ if (isNotEqual(state, sym, Adjusted))
+ return NULL;
+
+ // If we reach here, sym is not a constant and we don't know if it is == V.
+ // Make that assumption.
+ return AddEQ(state, sym, Adjusted);
+}
+
+// The logic for these will be handled in another ConstraintManager.
+const GRState*
+BasicConstraintManager::assumeSymLT(const GRState *state, SymbolRef sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) {
+ // Is 'V' the smallest possible value?
+ if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) {
+ // sym cannot be any value less than 'V'. This path is infeasible.
+ return NULL;
+ }
+
+ // FIXME: For now have assuming x < y be the same as assuming sym != V;
+ return assumeSymNE(state, sym, V, Adjustment);
+}
+
+const GRState*
+BasicConstraintManager::assumeSymGT(const GRState *state, SymbolRef sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) {
+ // Is 'V' the largest possible value?
+ if (V == llvm::APSInt::getMaxValue(V.getBitWidth(), V.isUnsigned())) {
+ // sym cannot be any value greater than 'V'. This path is infeasible.
+ return NULL;
+ }
+
+ // FIXME: For now have assuming x > y be the same as assuming sym != V;
+ return assumeSymNE(state, sym, V, Adjustment);
+}
+
+const GRState*
+BasicConstraintManager::assumeSymGE(const GRState *state, SymbolRef sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) {
+ // Reject a path if the value of sym is a constant X and !(X+Adj >= V).
+ if (const llvm::APSInt *X = getSymVal(state, sym)) {
+ bool isFeasible = (*X >= V-Adjustment);
+ return isFeasible ? state : NULL;
+ }
+
+ // Sym is not a constant, but it is worth looking to see if V is the
+ // maximum integer value.
+ if (V == llvm::APSInt::getMaxValue(V.getBitWidth(), V.isUnsigned())) {
+ llvm::APSInt Adjusted = V-Adjustment;
+
+ // If we know that sym != V (after adjustment), then this condition
+ // is infeasible since there is no other value greater than V.
+ bool isFeasible = !isNotEqual(state, sym, Adjusted);
+
+ // If the path is still feasible then as a consequence we know that
+ // 'sym+Adjustment == V' because there are no larger values.
+ // Add this constraint.
+ return isFeasible ? AddEQ(state, sym, Adjusted) : NULL;
+ }
+
+ return state;
+}
+
+const GRState*
+BasicConstraintManager::assumeSymLE(const GRState *state, SymbolRef sym,
+ const llvm::APSInt &V,
+ const llvm::APSInt &Adjustment) {
+ // Reject a path if the value of sym is a constant X and !(X+Adj <= V).
+ if (const llvm::APSInt* X = getSymVal(state, sym)) {
+ bool isFeasible = (*X <= V-Adjustment);
+ return isFeasible ? state : NULL;
+ }
+
+ // Sym is not a constant, but it is worth looking to see if V is the
+ // minimum integer value.
+ if (V == llvm::APSInt::getMinValue(V.getBitWidth(), V.isUnsigned())) {
+ llvm::APSInt Adjusted = V-Adjustment;
+
+ // If we know that sym != V (after adjustment), then this condition
+ // is infeasible since there is no other value less than V.
+ bool isFeasible = !isNotEqual(state, sym, Adjusted);
+
+ // If the path is still feasible then as a consequence we know that
+ // 'sym+Adjustment == V' because there are no smaller values.
+ // Add this constraint.
+ return isFeasible ? AddEQ(state, sym, Adjusted) : NULL;
+ }
+
+ return state;
+}
+
+const GRState* BasicConstraintManager::AddEQ(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V) {
+ // Create a new state with the old binding replaced.
+ return state->set<ConstEq>(sym, &state->getBasicVals().getValue(V));
+}
+
+const GRState* BasicConstraintManager::AddNE(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V) {
+
+ // First, retrieve the NE-set associated with the given symbol.
+ ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
+ GRState::IntSetTy S = T ? *T : ISetFactory.getEmptySet();
+
+ // Now add V to the NE set.
+ S = ISetFactory.add(S, &state->getBasicVals().getValue(V));
+
+ // Create a new state with the old binding replaced.
+ return state->set<ConstNotEq>(sym, S);
+}
+
+const llvm::APSInt* BasicConstraintManager::getSymVal(const GRState* state,
+ SymbolRef sym) const {
+ const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
+ return T ? *T : NULL;
+}
+
+bool BasicConstraintManager::isNotEqual(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V) const {
+
+ // Retrieve the NE-set associated with the given symbol.
+ const ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym);
+
+ // See if V is present in the NE-set.
+ return T ? T->contains(&state->getBasicVals().getValue(V)) : false;
+}
+
+bool BasicConstraintManager::isEqual(const GRState* state, SymbolRef sym,
+ const llvm::APSInt& V) const {
+ // Retrieve the EQ-set associated with the given symbol.
+ const ConstEqTy::data_type* T = state->get<ConstEq>(sym);
+ // See if V is present in the EQ-set.
+ return T ? **T == V : false;
+}
+
+/// Scan all symbols referenced by the constraints. If the symbol is not alive
+/// as marked in LSymbols, mark it as dead in DSymbols.
+const GRState*
+BasicConstraintManager::removeDeadBindings(const GRState* state,
+ SymbolReaper& SymReaper) {
+
+ ConstEqTy CE = state->get<ConstEq>();
+ ConstEqTy::Factory& CEFactory = state->get_context<ConstEq>();
+
+ for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) {
+ SymbolRef sym = I.getKey();
+ if (SymReaper.maybeDead(sym))
+ CE = CEFactory.remove(CE, sym);
+ }
+ state = state->set<ConstEq>(CE);
+
+ ConstNotEqTy CNE = state->get<ConstNotEq>();
+ ConstNotEqTy::Factory& CNEFactory = state->get_context<ConstNotEq>();
+
+ for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) {
+ SymbolRef sym = I.getKey();
+ if (SymReaper.maybeDead(sym))
+ CNE = CNEFactory.remove(CNE, sym);
+ }
+
+ return state->set<ConstNotEq>(CNE);
+}
+
+void BasicConstraintManager::print(const GRState* state, llvm::raw_ostream& Out,
+ const char* nl, const char *sep) {
+ // Print equality constraints.
+
+ ConstEqTy CE = state->get<ConstEq>();
+
+ if (!CE.isEmpty()) {
+ Out << nl << sep << "'==' constraints:";
+ for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I)
+ Out << nl << " $" << I.getKey() << " : " << *I.getData();
+ }
+
+ // Print != constraints.
+
+ ConstNotEqTy CNE = state->get<ConstNotEq>();
+
+ if (!CNE.isEmpty()) {
+ Out << nl << sep << "'!=' constraints:";
+
+ for (ConstNotEqTy::iterator I = CNE.begin(), EI = CNE.end(); I!=EI; ++I) {
+ Out << nl << " $" << I.getKey() << " : ";
+ bool isFirst = true;
+
+ GRState::IntSetTy::iterator J = I.getData().begin(),
+ EJ = I.getData().end();
+
+ for ( ; J != EJ; ++J) {
+ if (isFirst) isFirst = false;
+ else Out << ", ";
+
+ Out << (*J)->getSExtValue(); // Hack: should print to raw_ostream.
+ }
+ }
+ }
+}
diff --git a/lib/StaticAnalyzer/Core/BasicStore.cpp b/lib/StaticAnalyzer/Core/BasicStore.cpp
new file mode 100644
index 0000000000..abeac0d00c
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/BasicStore.cpp
@@ -0,0 +1,594 @@
+//== BasicStore.cpp - Basic map 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 BasicStore and BasicStoreManager classes.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprObjC.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "llvm/ADT/ImmutableMap.h"
+
+using namespace clang;
+using namespace ento;
+
+typedef llvm::ImmutableMap<const MemRegion*,SVal> BindingsTy;
+
+namespace {
+
+class BasicStoreSubRegionMap : public SubRegionMap {
+public:
+ BasicStoreSubRegionMap() {}
+
+ bool iterSubRegions(const MemRegion* R, Visitor& V) const {
+ return true; // Do nothing. No subregions.
+ }
+};
+
+class BasicStoreManager : public StoreManager {
+ BindingsTy::Factory VBFactory;
+public:
+ BasicStoreManager(GRStateManager& mgr)
+ : StoreManager(mgr), VBFactory(mgr.getAllocator()) {}
+
+ ~BasicStoreManager() {}
+
+ SubRegionMap *getSubRegionMap(Store store) {
+ return new BasicStoreSubRegionMap();
+ }
+
+ SVal Retrieve(Store store, Loc loc, QualType T = QualType());
+
+ Store InvalidateRegion(Store store, const MemRegion *R, const Expr *E,
+ unsigned Count, InvalidatedSymbols *IS);
+
+ Store InvalidateRegions(Store store, const MemRegion * const *Begin,
+ const MemRegion * const *End, const Expr *E,
+ unsigned Count, InvalidatedSymbols *IS,
+ bool invalidateGlobals, InvalidatedRegions *Regions);
+
+ Store scanForIvars(Stmt *B, const Decl* SelfDecl,
+ const MemRegion *SelfRegion, Store St);
+
+ Store Bind(Store St, Loc loc, SVal V);
+ Store Remove(Store St, Loc loc);
+ Store getInitialStore(const LocationContext *InitLoc);
+
+ Store BindCompoundLiteral(Store store, const CompoundLiteralExpr*,
+ const LocationContext*, SVal val) {
+ return store;
+ }
+
+ /// ArrayToPointer - Used by ExprEngine::VistCast to handle implicit
+ /// conversions between arrays and pointers.
+ SVal ArrayToPointer(Loc Array) { return Array; }
+
+ /// removeDeadBindings - Scans a BasicStore of 'state' for dead values.
+ /// It updatees the GRState object in place with the values removed.
+ Store removeDeadBindings(Store store, const StackFrameContext *LCtx,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+
+ void iterBindings(Store store, BindingsHandler& f);
+
+ Store BindDecl(Store store, const VarRegion *VR, SVal InitVal) {
+ return BindDeclInternal(store, VR, &InitVal);
+ }
+
+ Store BindDeclWithNoInit(Store store, const VarRegion *VR) {
+ return BindDeclInternal(store, VR, 0);
+ }
+
+ Store BindDeclInternal(Store store, const VarRegion *VR, SVal *InitVal);
+
+ static inline BindingsTy GetBindings(Store store) {
+ return BindingsTy(static_cast<const BindingsTy::TreeTy*>(store));
+ }
+
+ void print(Store store, llvm::raw_ostream& Out, const char* nl,
+ const char *sep);
+
+private:
+ SVal LazyRetrieve(Store store, const TypedRegion *R);
+};
+
+} // end anonymous namespace
+
+
+StoreManager* ento::CreateBasicStoreManager(GRStateManager& StMgr) {
+ return new BasicStoreManager(StMgr);
+}
+
+static bool isHigherOrderRawPtr(QualType T, ASTContext &C) {
+ bool foundPointer = false;
+ while (1) {
+ const PointerType *PT = T->getAs<PointerType>();
+ if (!PT) {
+ if (!foundPointer)
+ return false;
+
+ // intptr_t* or intptr_t**, etc?
+ if (T->isIntegerType() && C.getTypeSize(T) == C.getTypeSize(C.VoidPtrTy))
+ return true;
+
+ QualType X = C.getCanonicalType(T).getUnqualifiedType();
+ return X == C.VoidTy;
+ }
+
+ foundPointer = true;
+ T = PT->getPointeeType();
+ }
+}
+
+SVal BasicStoreManager::LazyRetrieve(Store store, const TypedRegion *R) {
+ const VarRegion *VR = dyn_cast<VarRegion>(R);
+ if (!VR)
+ return UnknownVal();
+
+ const VarDecl *VD = VR->getDecl();
+ QualType T = VD->getType();
+
+ // Only handle simple types that we can symbolicate.
+ if (!SymbolManager::canSymbolicate(T) || !T->isScalarType())
+ return UnknownVal();
+
+ // Globals and parameters start with symbolic values.
+ // Local variables initially are undefined.
+
+ // Non-static globals may have had their values reset by InvalidateRegions.
+ const MemSpaceRegion *MS = VR->getMemorySpace();
+ if (isa<NonStaticGlobalSpaceRegion>(MS)) {
+ BindingsTy B = GetBindings(store);
+ // FIXME: Copy-and-pasted from RegionStore.cpp.
+ if (BindingsTy::data_type *Val = B.lookup(MS)) {
+ if (SymbolRef parentSym = Val->getAsSymbol())
+ return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
+
+ if (Val->isZeroConstant())
+ return svalBuilder.makeZeroVal(T);
+
+ if (Val->isUnknownOrUndef())
+ return *Val;
+
+ assert(0 && "Unknown default value.");
+ }
+ }
+
+ if (VR->hasGlobalsOrParametersStorage() ||
+ isa<UnknownSpaceRegion>(VR->getMemorySpace()))
+ return svalBuilder.getRegionValueSymbolVal(R);
+
+ return UndefinedVal();
+}
+
+SVal BasicStoreManager::Retrieve(Store store, Loc loc, QualType T) {
+ if (isa<UnknownVal>(loc))
+ return UnknownVal();
+
+ assert(!isa<UndefinedVal>(loc));
+
+ switch (loc.getSubKind()) {
+
+ case loc::MemRegionKind: {
+ const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
+
+ if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) ||
+ isa<CXXThisRegion>(R)))
+ return UnknownVal();
+
+ BindingsTy B = GetBindings(store);
+ BindingsTy::data_type *Val = B.lookup(R);
+ const TypedRegion *TR = cast<TypedRegion>(R);
+
+ if (Val)
+ return CastRetrievedVal(*Val, TR, T);
+
+ SVal V = LazyRetrieve(store, TR);
+ return V.isUnknownOrUndef() ? V : CastRetrievedVal(V, TR, T);
+ }
+
+ case loc::ObjCPropRefKind:
+ case loc::ConcreteIntKind:
+ // Support direct accesses to memory. It's up to individual checkers
+ // to flag an error.
+ return UnknownVal();
+
+ default:
+ assert (false && "Invalid Loc.");
+ break;
+ }
+
+ return UnknownVal();
+}
+
+Store BasicStoreManager::Bind(Store store, Loc loc, SVal V) {
+ if (isa<loc::ConcreteInt>(loc))
+ return store;
+
+ const MemRegion* R = cast<loc::MemRegionVal>(loc).getRegion();
+
+ // Special case: a default symbol assigned to the NonStaticGlobalsSpaceRegion
+ // that is used to derive other symbols.
+ if (isa<NonStaticGlobalSpaceRegion>(R)) {
+ BindingsTy B = GetBindings(store);
+ return VBFactory.add(B, R, V).getRoot();
+ }
+
+ // Special case: handle store of pointer values (Loc) to pointers via
+ // a cast to intXX_t*, void*, etc. This is needed to handle
+ // OSCompareAndSwap32Barrier/OSCompareAndSwap64Barrier.
+ if (isa<Loc>(V) || isa<nonloc::LocAsInteger>(V))
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ // FIXME: Should check for index 0.
+ QualType T = ER->getLocationType();
+
+ if (isHigherOrderRawPtr(T, Ctx))
+ R = ER->getSuperRegion();
+ }
+
+ if (!(isa<VarRegion>(R) || isa<ObjCIvarRegion>(R) || isa<CXXThisRegion>(R)))
+ return store;
+
+ const TypedRegion *TyR = cast<TypedRegion>(R);
+
+ // Do not bind to arrays. We need to explicitly check for this so that
+ // we do not encounter any weirdness of trying to load/store from arrays.
+ if (TyR->isBoundable() && TyR->getValueType()->isArrayType())
+ return store;
+
+ if (nonloc::LocAsInteger *X = dyn_cast<nonloc::LocAsInteger>(&V)) {
+ // Only convert 'V' to a location iff the underlying region type
+ // is a location as well.
+ // FIXME: We are allowing a store of an arbitrary location to
+ // a pointer.