aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/RegionStore.cpp
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/RegionStore.cpp
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/RegionStore.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp1917
1 files changed, 1917 insertions, 0 deletions
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
new file mode 100644
index 0000000000..d5af1c2747
--- /dev/null
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -0,0 +1,1917 @@
+//== RegionStore.cpp - Field-sensitive store model --------------*- 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 basic region store model. In this model, we do have field
+// sensitivity. But we assume nothing about the heap shape. So recursive data
+// structures are largely ignored. Basically we do 1-limiting analysis.
+// Parameter pointers are assumed with no aliasing. Pointee objects of
+// parameters are created lazily.
+//
+//===----------------------------------------------------------------------===//
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/AnalysisContext.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
+#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
+#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
+#include "llvm/ADT/ImmutableList.h"
+#include "llvm/ADT/ImmutableMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace ento;
+using llvm::Optional;
+
+//===----------------------------------------------------------------------===//
+// Representation of binding keys.
+//===----------------------------------------------------------------------===//
+
+namespace {
+class BindingKey {
+public:
+ enum Kind { Direct = 0x0, Default = 0x1 };
+private:
+ llvm ::PointerIntPair<const MemRegion*, 1> P;
+ uint64_t Offset;
+
+ explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k)
+ : P(r, (unsigned) k), Offset(offset) {}
+public:
+
+ bool isDirect() const { return P.getInt() == Direct; }
+
+ const MemRegion *getRegion() const { return P.getPointer(); }
+ uint64_t getOffset() const { return Offset; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ ID.AddPointer(P.getOpaqueValue());
+ ID.AddInteger(Offset);
+ }
+
+ static BindingKey Make(const MemRegion *R, Kind k);
+
+ bool operator<(const BindingKey &X) const {
+ if (P.getOpaqueValue() < X.P.getOpaqueValue())
+ return true;
+ if (P.getOpaqueValue() > X.P.getOpaqueValue())
+ return false;
+ return Offset < X.Offset;
+ }
+
+ bool operator==(const BindingKey &X) const {
+ return P.getOpaqueValue() == X.P.getOpaqueValue() &&
+ Offset == X.Offset;
+ }
+
+ bool isValid() const {
+ return getRegion() != NULL;
+ }
+};
+} // end anonymous namespace
+
+BindingKey BindingKey::Make(const MemRegion *R, Kind k) {
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ const RegionRawOffset &O = ER->getAsArrayOffset();
+
+ // FIXME: There are some ElementRegions for which we cannot compute
+ // raw offsets yet, including regions with symbolic offsets. These will be
+ // ignored by the store.
+ return BindingKey(O.getRegion(), O.getOffset().getQuantity(), k);
+ }
+
+ return BindingKey(R, 0, k);
+}
+
+namespace llvm {
+ static inline
+ llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingKey K) {
+ os << '(' << K.getRegion() << ',' << K.getOffset()
+ << ',' << (K.isDirect() ? "direct" : "default")
+ << ')';
+ return os;
+ }
+} // end llvm namespace
+
+//===----------------------------------------------------------------------===//
+// Actual Store type.
+//===----------------------------------------------------------------------===//
+
+typedef llvm::ImmutableMap<BindingKey, SVal> RegionBindings;
+
+//===----------------------------------------------------------------------===//
+// Fine-grained control of RegionStoreManager.
+//===----------------------------------------------------------------------===//
+
+namespace {
+struct minimal_features_tag {};
+struct maximal_features_tag {};
+
+class RegionStoreFeatures {
+ bool SupportsFields;
+public:
+ RegionStoreFeatures(minimal_features_tag) :
+ SupportsFields(false) {}
+
+ RegionStoreFeatures(maximal_features_tag) :
+ SupportsFields(true) {}
+
+ void enableFields(bool t) { SupportsFields = t; }
+
+ bool supportsFields() const { return SupportsFields; }
+};
+}
+
+//===----------------------------------------------------------------------===//
+// Main RegionStore logic.
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class RegionStoreSubRegionMap : public SubRegionMap {
+public:
+ typedef llvm::ImmutableSet<const MemRegion*> Set;
+ typedef llvm::DenseMap<const MemRegion*, Set> Map;
+private:
+ Set::Factory F;
+ Map M;
+public:
+ bool add(const MemRegion* Parent, const MemRegion* SubRegion) {
+ Map::iterator I = M.find(Parent);
+
+ if (I == M.end()) {
+ M.insert(std::make_pair(Parent, F.add(F.getEmptySet(), SubRegion)));
+ return true;
+ }
+
+ I->second = F.add(I->second, SubRegion);
+ return false;
+ }
+
+ void process(llvm::SmallVectorImpl<const SubRegion*> &WL, const SubRegion *R);
+
+ ~RegionStoreSubRegionMap() {}
+
+ const Set *getSubRegions(const MemRegion *Parent) const {
+ Map::const_iterator I = M.find(Parent);
+ return I == M.end() ? NULL : &I->second;
+ }
+
+ bool iterSubRegions(const MemRegion* Parent, Visitor& V) const {
+ Map::const_iterator I = M.find(Parent);
+
+ if (I == M.end())
+ return true;
+
+ Set S = I->second;
+ for (Set::iterator SI=S.begin(),SE=S.end(); SI != SE; ++SI) {
+ if (!V.Visit(Parent, *SI))
+ return false;
+ }
+
+ return true;
+ }
+};
+
+void
+RegionStoreSubRegionMap::process(llvm::SmallVectorImpl<const SubRegion*> &WL,
+ const SubRegion *R) {
+ const MemRegion *superR = R->getSuperRegion();
+ if (add(superR, R))
+ if (const SubRegion *sr = dyn_cast<SubRegion>(superR))
+ WL.push_back(sr);
+}
+
+class RegionStoreManager : public StoreManager {
+ const RegionStoreFeatures Features;
+ RegionBindings::Factory RBFactory;
+
+public:
+ RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f)
+ : StoreManager(mgr),
+ Features(f),
+ RBFactory(mgr.getAllocator()) {}
+
+ SubRegionMap *getSubRegionMap(Store store) {
+ return getRegionStoreSubRegionMap(store);
+ }
+
+ RegionStoreSubRegionMap *getRegionStoreSubRegionMap(Store store);
+
+ Optional<SVal> getDirectBinding(RegionBindings B, const MemRegion *R);
+ /// getDefaultBinding - Returns an SVal* representing an optional default
+ /// binding associated with a region and its subregions.
+ Optional<SVal> getDefaultBinding(RegionBindings B, const MemRegion *R);
+
+ /// setImplicitDefaultValue - Set the default binding for the provided
+ /// MemRegion to the value implicitly defined for compound literals when
+ /// the value is not specified.
+ Store setImplicitDefaultValue(Store store, const MemRegion *R, QualType T);
+
+ /// ArrayToPointer - Emulates the "decay" of an array to a pointer
+ /// type. 'Array' represents the lvalue of the array being decayed
+ /// to a pointer, and the returned SVal represents the decayed
+ /// version of that lvalue (i.e., a pointer to the first element of
+ /// the array). This is called by ExprEngine when evaluating
+ /// casts from arrays to pointers.
+ SVal ArrayToPointer(Loc Array);
+
+ /// For DerivedToBase casts, create a CXXBaseObjectRegion and return it.
+ virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType);
+
+ SVal evalBinOp(BinaryOperator::Opcode Op,Loc L, NonLoc R, QualType resultTy);
+
+ Store getInitialStore(const LocationContext *InitLoc) {
+ return RBFactory.getEmptyMap().getRoot();
+ }
+
+ //===-------------------------------------------------------------------===//
+ // Binding values to regions.
+ //===-------------------------------------------------------------------===//
+
+ Store InvalidateRegions(Store store,
+ const MemRegion * const *Begin,
+ const MemRegion * const *End,
+ const Expr *E, unsigned Count,
+ InvalidatedSymbols *IS,
+ bool invalidateGlobals,
+ InvalidatedRegions *Regions);
+
+public: // Made public for helper classes.
+
+ void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
+ RegionStoreSubRegionMap &M);
+
+ RegionBindings addBinding(RegionBindings B, BindingKey K, SVal V);
+
+ RegionBindings addBinding(RegionBindings B, const MemRegion *R,
+ BindingKey::Kind k, SVal V);
+
+ const SVal *lookup(RegionBindings B, BindingKey K);
+ const SVal *lookup(RegionBindings B, const MemRegion *R, BindingKey::Kind k);
+
+ RegionBindings removeBinding(RegionBindings B, BindingKey K);
+ RegionBindings removeBinding(RegionBindings B, const MemRegion *R,
+ BindingKey::Kind k);
+
+ RegionBindings removeBinding(RegionBindings B, const MemRegion *R) {
+ return removeBinding(removeBinding(B, R, BindingKey::Direct), R,
+ BindingKey::Default);
+ }
+
+public: // Part of public interface to class.
+
+ Store Bind(Store store, Loc LV, SVal V);
+
+ // BindDefault is only used to initialize a region with a default value.
+ Store BindDefault(Store store, const MemRegion *R, SVal V) {
+ RegionBindings B = GetRegionBindings(store);
+ assert(!lookup(B, R, BindingKey::Default));
+ assert(!lookup(B, R, BindingKey::Direct));
+ return addBinding(B, R, BindingKey::Default, V).getRoot();
+ }
+
+ Store BindCompoundLiteral(Store store, const CompoundLiteralExpr* CL,
+ const LocationContext *LC, SVal V);
+
+ Store BindDecl(Store store, const VarRegion *VR, SVal InitVal);
+
+ Store BindDeclWithNoInit(Store store, const VarRegion *) {
+ return store;
+ }
+
+ /// BindStruct - Bind a compound value to a structure.
+ Store BindStruct(Store store, const TypedRegion* R, SVal V);
+
+ Store BindArray(Store store, const TypedRegion* R, SVal V);
+
+ /// KillStruct - Set the entire struct to unknown.
+ Store KillStruct(Store store, const TypedRegion* R, SVal DefaultVal);
+
+ Store Remove(Store store, Loc LV);
+
+
+ //===------------------------------------------------------------------===//
+ // Loading values from regions.
+ //===------------------------------------------------------------------===//
+
+ /// The high level logic for this method is this:
+ /// Retrieve (L)
+ /// if L has binding
+ /// return L's binding
+ /// else if L is in killset
+ /// return unknown
+ /// else
+ /// if L is on stack or heap
+ /// return undefined
+ /// else
+ /// return symbolic
+ SVal Retrieve(Store store, Loc L, QualType T = QualType());
+
+ SVal RetrieveElement(Store store, const ElementRegion *R);
+
+ SVal RetrieveField(Store store, const FieldRegion *R);
+
+ SVal RetrieveObjCIvar(Store store, const ObjCIvarRegion *R);
+
+ SVal RetrieveVar(Store store, const VarRegion *R);
+
+ SVal RetrieveLazySymbol(const TypedRegion *R);
+
+ SVal RetrieveFieldOrElementCommon(Store store, const TypedRegion *R,
+ QualType Ty, const MemRegion *superR);
+
+ /// Retrieve the values in a struct and return a CompoundVal, used when doing
+ /// struct copy:
+ /// struct s x, y;
+ /// x = y;
+ /// y's value is retrieved by this method.
+ SVal RetrieveStruct(Store store, const TypedRegion* R);
+
+ SVal RetrieveArray(Store store, const TypedRegion* R);
+
+ /// Used to lazily generate derived symbols for bindings that are defined
+ /// implicitly by default bindings in a super region.
+ Optional<SVal> RetrieveDerivedDefaultValue(RegionBindings B,
+ const MemRegion *superR,
+ const TypedRegion *R, QualType Ty);
+
+ /// Get the state and region whose binding this region R corresponds to.
+ std::pair<Store, const MemRegion*>
+ GetLazyBinding(RegionBindings B, const MemRegion *R);
+
+ Store CopyLazyBindings(nonloc::LazyCompoundVal V, Store store,
+ const TypedRegion *R);
+
+ //===------------------------------------------------------------------===//
+ // State pruning.
+ //===------------------------------------------------------------------===//
+
+ /// removeDeadBindings - Scans the RegionStore of 'state' for dead values.
+ /// It returns a new Store with these values removed.
+ Store removeDeadBindings(Store store, const StackFrameContext *LCtx,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+
+ Store enterStackFrame(const GRState *state, const StackFrameContext *frame);
+
+ //===------------------------------------------------------------------===//
+ // Region "extents".
+ //===------------------------------------------------------------------===//
+
+ // FIXME: This method will soon be eliminated; see the note in Store.h.
+ DefinedOrUnknownSVal getSizeInElements(const GRState *state,
+ const MemRegion* R, QualType EleTy);
+
+ //===------------------------------------------------------------------===//
+ // Utility methods.
+ //===------------------------------------------------------------------===//
+
+ static inline RegionBindings GetRegionBindings(Store store) {
+ return RegionBindings(static_cast<const RegionBindings::TreeTy*>(store));
+ }
+
+ void print(Store store, llvm::raw_ostream& Out, const char* nl,
+ const char *sep);
+
+ void iterBindings(Store store, BindingsHandler& f) {
+ RegionBindings B = GetRegionBindings(store);
+ for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
+ const BindingKey &K = I.getKey();
+ if (!K.isDirect())
+ continue;
+ if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion())) {
+ // FIXME: Possibly incorporate the offset?
+ if (!f.HandleBinding(*this, store, R, I.getData()))
+ return;
+ }
+ }
+ }
+};
+
+} // end anonymous namespace
+
+//===----------------------------------------------------------------------===//
+// RegionStore creation.
+//===----------------------------------------------------------------------===//
+
+StoreManager *ento::CreateRegionStoreManager(GRStateManager& StMgr) {
+ RegionStoreFeatures F = maximal_features_tag();
+ return new RegionStoreManager(StMgr, F);
+}
+
+StoreManager *ento::CreateFieldsOnlyRegionStoreManager(GRStateManager &StMgr) {
+ RegionStoreFeatures F = minimal_features_tag();
+ F.enableFields(true);
+ return new RegionStoreManager(StMgr, F);
+}
+
+
+RegionStoreSubRegionMap*
+RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
+ RegionBindings B = GetRegionBindings(store);
+ RegionStoreSubRegionMap *M = new RegionStoreSubRegionMap();
+
+ llvm::SmallVector<const SubRegion*, 10> WL;
+
+ for (RegionBindings::iterator I=B.begin(), E=B.end(); I!=E; ++I)
+ if (const SubRegion *R = dyn_cast<SubRegion>(I.getKey().getRegion()))
+ M->process(WL, R);
+
+ // We also need to record in the subregion map "intermediate" regions that
+ // don't have direct bindings but are super regions of those that do.
+ while (!WL.empty()) {
+ const SubRegion *R = WL.back();
+ WL.pop_back();
+ M->process(WL, R);
+ }
+
+ return M;
+}
+
+//===----------------------------------------------------------------------===//
+// Region Cluster analysis.
+//===----------------------------------------------------------------------===//
+
+namespace {
+template <typename DERIVED>
+class ClusterAnalysis {
+protected:
+ typedef BumpVector<BindingKey> RegionCluster;
+ typedef llvm::DenseMap<const MemRegion *, RegionCluster *> ClusterMap;
+ llvm::DenseMap<const RegionCluster*, unsigned> Visited;
+ typedef llvm::SmallVector<std::pair<const MemRegion *, RegionCluster*>, 10>
+ WorkList;
+
+ BumpVectorContext BVC;
+ ClusterMap ClusterM;
+ WorkList WL;
+
+ RegionStoreManager &RM;
+ ASTContext &Ctx;
+ SValBuilder &svalBuilder;
+
+ RegionBindings B;
+
+ const bool includeGlobals;
+
+public:
+ ClusterAnalysis(RegionStoreManager &rm, GRStateManager &StateMgr,
+ RegionBindings b, const bool includeGlobals)
+ : RM(rm), Ctx(StateMgr.getContext()),
+ svalBuilder(StateMgr.getSValBuilder()),
+ B(b), includeGlobals(includeGlobals) {}
+
+ RegionBindings getRegionBindings() const { return B; }
+
+ RegionCluster &AddToCluster(BindingKey K) {
+ const MemRegion *R = K.getRegion();
+ const MemRegion *baseR = R->getBaseRegion();
+ RegionCluster &C = getCluster(baseR);
+ C.push_back(K, BVC);
+ static_cast<DERIVED*>(this)->VisitAddedToCluster(baseR, C);
+ return C;
+ }
+
+ bool isVisited(const MemRegion *R) {
+ return (bool) Visited[&getCluster(R->getBaseRegion())];
+ }
+
+ RegionCluster& getCluster(const MemRegion *R) {
+ RegionCluster *&CRef = ClusterM[R];
+ if (!CRef) {
+ void *Mem = BVC.getAllocator().template Allocate<RegionCluster>();
+ CRef = new (Mem) RegionCluster(BVC, 10);
+ }
+ return *CRef;
+ }
+
+ void GenerateClusters() {
+ // Scan the entire set of bindings and make the region clusters.
+ for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
+ RegionCluster &C = AddToCluster(RI.getKey());
+ if (const MemRegion *R = RI.getData().getAsRegion()) {
+ // Generate a cluster, but don't add the region to the cluster
+ // if there aren't any bindings.
+ getCluster(R->getBaseRegion());
+ }
+ if (includeGlobals) {
+ const MemRegion *R = RI.getKey().getRegion();
+ if (isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace()))
+ AddToWorkList(R, C);
+ }
+ }
+ }
+
+ bool AddToWorkList(const MemRegion *R, RegionCluster &C) {
+ if (unsigned &visited = Visited[&C])
+ return false;
+ else
+ visited = 1;
+
+ WL.push_back(std::make_pair(R, &C));
+ return true;
+ }
+
+ bool AddToWorkList(BindingKey K) {
+ return AddToWorkList(K.getRegion());
+ }
+
+ bool AddToWorkList(const MemRegion *R) {
+ const MemRegion *baseR = R->getBaseRegion();
+ return AddToWorkList(baseR, getCluster(baseR));
+ }
+
+ void RunWorkList() {
+ while (!WL.empty()) {
+ const MemRegion *baseR;
+ RegionCluster *C;
+ llvm::tie(baseR, C) = WL.back();
+ WL.pop_back();
+
+ // First visit the cluster.
+ static_cast<DERIVED*>(this)->VisitCluster(baseR, C->begin(), C->end());
+
+ // Next, visit the base region.
+ static_cast<DERIVED*>(this)->VisitBaseRegion(baseR);
+ }
+ }
+
+public:
+ void VisitAddedToCluster(const MemRegion *baseR, RegionCluster &C) {}
+ void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E) {}
+ void VisitBaseRegion(const MemRegion *baseR) {}
+};
+}
+
+//===----------------------------------------------------------------------===//
+// Binding invalidation.
+//===----------------------------------------------------------------------===//
+
+void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
+ const MemRegion *R,
+ RegionStoreSubRegionMap &M) {
+
+ if (const RegionStoreSubRegionMap::Set *S = M.getSubRegions(R))
+ for (RegionStoreSubRegionMap::Set::iterator I = S->begin(), E = S->end();
+ I != E; ++I)
+ RemoveSubRegionBindings(B, *I, M);
+
+ B = removeBinding(B, R);
+}
+
+namespace {
+class InvalidateRegionsWorker : public ClusterAnalysis<InvalidateRegionsWorker>
+{
+ const Expr *Ex;
+ unsigned Count;
+ StoreManager::InvalidatedSymbols *IS;
+ StoreManager::InvalidatedRegions *Regions;
+public:
+ InvalidateRegionsWorker(RegionStoreManager &rm,
+ GRStateManager &stateMgr,
+ RegionBindings b,
+ const Expr *ex, unsigned count,
+ StoreManager::InvalidatedSymbols *is,
+ StoreManager::InvalidatedRegions *r,
+ bool includeGlobals)
+ : ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
+ Ex(ex), Count(count), IS(is), Regions(r) {}
+
+ void VisitCluster(const MemRegion *baseR, BindingKey *I, BindingKey *E);
+ void VisitBaseRegion(const MemRegion *baseR);
+
+private:
+ void VisitBinding(SVal V);
+};
+}
+
+void InvalidateRegionsWorker::VisitBinding(SVal V) {
+ // A symbol? Mark it touched by the invalidation.
+ if (IS)
+ if (SymbolRef Sym = V.getAsSymbol())
+ IS->insert(Sym);
+
+ if (const MemRegion *R = V.getAsRegion()) {
+ AddToWorkList(R);
+ return;
+ }
+
+ // Is it a LazyCompoundVal? All references get invalidated as well.
+ if (const nonloc::LazyCompoundVal *LCS =
+ dyn_cast<nonloc::LazyCompoundVal>(&V)) {
+
+ const MemRegion *LazyR = LCS->getRegion();
+ RegionBindings B = RegionStoreManager::GetRegionBindings(LCS->getStore());
+
+ for (RegionBindings::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI){
+ const SubRegion *baseR = dyn_cast<SubRegion>(RI.getKey().getRegion());
+ if (baseR && baseR->isSubRegionOf(LazyR))
+ VisitBinding(RI.getData());
+ }
+
+ return;
+ }
+}
+
+void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
+ BindingKey *I, BindingKey *E) {
+ for ( ; I != E; ++I) {
+ // Get the old binding. Is it a region? If so, add it to the worklist.
+ const BindingKey &K = *I;
+ if (const SVal *V = RM.lookup(B, K))
+ VisitBinding(*V);
+
+ B = RM.removeBinding(B, K);
+ }
+}
+
+void InvalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
+ if (IS) {
+ // Symbolic region? Mark that symbol touched by the invalidation.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
+ IS->insert(SR->getSymbol());
+ }
+
+ // BlockDataRegion? If so, invalidate captured variables that are passed
+ // by reference.
+ if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) {
+ for (BlockDataRegion::referenced_vars_iterator
+ BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ;
+ BI != BE; ++BI) {
+ const VarRegion *VR = *BI;
+ const VarDecl *VD = VR->getDecl();
+ if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
+ AddToWorkList(VR);
+ }
+ return;
+ }
+
+ // Otherwise, we have a normal data region. Record that we touched the region.
+ if (Regions)
+ Regions->push_back(baseR);
+
+ if (isa<AllocaRegion>(baseR) || isa<SymbolicRegion>(baseR)) {
+ // Invalidate the region by setting its default value to
+ // conjured symbol. The type of the symbol is irrelavant.
+ DefinedOrUnknownSVal V =
+ svalBuilder.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy, Count);
+ B = RM.addBinding(B, baseR, BindingKey::Default, V);
+ return;
+ }
+
+ if (!baseR->isBoundable())
+ return;
+
+ const TypedRegion *TR = cast<TypedRegion>(baseR);
+ QualType T = TR->getValueType();
+
+ // Invalidate the binding.
+ if (T->isStructureType()) {
+ // Invalidate the region by setting its default value to
+ // conjured symbol. The type of the symbol is irrelavant.
+ DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, Ctx.IntTy,
+ Count);
+ B = RM.addBinding(B, baseR, BindingKey::Default, V);
+ return;
+ }
+
+ if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
+ // Set the default value of the array to conjured symbol.
+ DefinedOrUnknownSVal V =
+ svalBuilder.getConjuredSymbolVal(baseR, Ex, AT->getElementType(), Count);
+ B = RM.addBinding(B, baseR, BindingKey::Default, V);
+ return;
+ }
+
+ if (includeGlobals &&
+ isa<NonStaticGlobalSpaceRegion>(baseR->getMemorySpace())) {
+ // If the region is a global and we are invalidating all globals,
+ // just erase the entry. This causes all globals to be lazily
+ // symbolicated from the same base symbol.
+ B = RM.removeBinding(B, baseR);
+ return;
+ }
+
+
+ DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, T, Count);
+ assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
+ B = RM.addBinding(B, baseR, BindingKey::Direct, V);
+}
+
+Store RegionStoreManager::InvalidateRegions(Store store,
+ const MemRegion * const *I,
+ const MemRegion * const *E,
+ const Expr *Ex, unsigned Count,
+ InvalidatedSymbols *IS,
+ bool invalidateGlobals,
+ InvalidatedRegions *Regions) {
+ InvalidateRegionsWorker W(*this, StateMgr,
+ RegionStoreManager::GetRegionBindings(store),
+ Ex, Count, IS, Regions, invalidateGlobals);
+
+ // Scan the bindings and generate the clusters.
+ W.GenerateClusters();
+
+ // Add I .. E to the worklist.
+ for ( ; I != E; ++I)
+ W.AddToWorkList(*I);
+
+ W.RunWorkList();
+
+ // Return the new bindings.
+ RegionBindings B = W.getRegionBindings();
+
+ if (invalidateGlobals) {
+ // Bind the non-static globals memory space to a new symbol that we will
+ // use to derive the bindings for all non-static globals.
+ const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion();
+ SVal V =
+ svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, Ex,
+ /* symbol type, doesn't matter */ Ctx.IntTy,
+ Count);
+ B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V);
+
+ // Even if there are no bindings in the global scope, we still need to
+ // record that we touched it.
+ if (Regions)
+ Regions->push_back(GS);
+ }
+
+ return B.getRoot();
+}
+
+//===----------------------------------------------------------------------===//
+// Extents for regions.
+//===----------------------------------------------------------------------===//
+
+DefinedOrUnknownSVal RegionStoreManager::getSizeInElements(const GRState *state,
+ const MemRegion *R,
+ QualType EleTy) {
+ SVal Size = cast<SubRegion>(R)->getExtent(svalBuilder);
+ const llvm::APSInt *SizeInt = svalBuilder.getKnownValue(state, Size);
+ if (!SizeInt)
+ return UnknownVal();
+
+ CharUnits RegionSize = CharUnits::fromQuantity(SizeInt->getSExtValue());
+
+ if (Ctx.getAsVariableArrayType(EleTy)) {
+ // FIXME: We need to track extra state to properly record the size
+ // of VLAs. Returning UnknownVal here, however, is a stop-gap so that
+ // we don't have a divide-by-zero below.
+ return UnknownVal();
+ }
+
+ CharUnits EleSize = Ctx.getTypeSizeInChars(EleTy);
+
+ // If a variable is reinterpreted as a type that doesn't fit into a larger
+ // type evenly, round it down.
+ // This is a signed value, since it's used in arithmetic with signed indices.
+ return svalBuilder.makeIntVal(RegionSize / EleSize, false);
+}
+
+//===----------------------------------------------------------------------===//
+// Location and region casting.
+//===----------------------------------------------------------------------===//
+
+/// ArrayToPointer - Emulates the "decay" of an array to a pointer
+/// type. 'Array' represents the lvalue of the array being decayed
+/// to a pointer, and the returned SVal represents the decayed
+/// version of that lvalue (i.e., a pointer to the first element of
+/// the array). This is called by ExprEngine when evaluating casts
+/// from arrays to pointers.
+SVal RegionStoreManager::ArrayToPointer(Loc Array) {
+ if (!isa<loc::MemRegionVal>(Array))
+ return UnknownVal();
+
+ const MemRegion* R = cast<loc::MemRegionVal>(&Array)->getRegion();
+ const TypedRegion* ArrayR = dyn_cast<TypedRegion>(R);
+
+ if (!ArrayR)
+ return UnknownVal();
+
+ // Strip off typedefs from the ArrayRegion's ValueType.
+ QualType T = ArrayR->getValueType().getDesugaredType(Ctx);
+ const ArrayType *AT = cast<ArrayType>(T);
+ T = AT->getElementType();
+
+ NonLoc ZeroIdx = svalBuilder.makeZeroArrayIndex();
+ return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, Ctx));
+}
+
+SVal RegionStoreManager::evalDerivedToBase(SVal derived, QualType baseType) {
+ const CXXRecordDecl *baseDecl;
+ if (baseType->isPointerType())
+ baseDecl = baseType->getCXXRecordDeclForPointerType();
+ else
+ baseDecl = baseType->getAsCXXRecordDecl();
+
+ assert(baseDecl && "not a CXXRecordDecl?");
+
+ loc::MemRegionVal *derivedRegVal = dyn_cast<loc::MemRegionVal>(&derived);
+ if (!derivedRegVal)
+ return derived;
+
+ const MemRegion *baseReg =
+ MRMgr.getCXXBaseObjectRegion(baseDecl, derivedRegVal->getRegion());
+
+ return loc::MemRegionVal(baseReg);
+}
+//===----------------------------------------------------------------------===//
+// Pointer arithmetic.
+//===----------------------------------------------------------------------===//
+
+SVal RegionStoreManager::evalBinOp(BinaryOperator::Opcode Op, Loc L, NonLoc R,
+ QualType resultTy) {
+ // Assume the base location is MemRegionVal.
+ if (!isa<loc::MemRegionVal>(L))
+ return UnknownVal();
+
+ // Special case for zero RHS.
+ if (R.isZeroConstant()) {
+ switch (Op) {
+ default:
+ // Handle it normally.
+ break;
+ case BO_Add:
+ case BO_Sub:
+ // FIXME: does this need to be casted to match resultTy?
+ return L;
+ }
+ }
+
+ const MemRegion* MR = cast<loc::MemRegionVal>(L).getRegion();
+ const ElementRegion *ER = 0;
+
+ switch (MR->getKind()) {
+ case MemRegion::SymbolicRegionKind: {
+ const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
+ SymbolRef Sym = SR->getSymbol();
+ QualType T = Sym->getType(Ctx);
+ QualType EleTy;
+
+ if (const PointerType *PT = T->getAs<PointerType>())
+ EleTy = PT->getPointeeType();
+ else
+ EleTy = T->getAs<ObjCObjectPointerType>()->getPointeeType();
+
+ const NonLoc &ZeroIdx = svalBuilder.makeZeroArrayIndex();
+ ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, Ctx);
+ break;
+ }
+ case MemRegion::AllocaRegionKind: {
+ const AllocaRegion *AR = cast<AllocaRegion>(MR);
+ QualType EleTy = Ctx.CharTy; // Create an ElementRegion of bytes.
+ NonLoc ZeroIdx = svalBuilder.makeZeroArrayIndex();
+ ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, Ctx);
+ break;
+ }
+
+ case MemRegion::ElementRegionKind: {
+ ER = cast<ElementRegion>(MR);
+ break;
+ }
+
+ // Not yet handled.
+ case MemRegion::VarRegionKind:
+ case MemRegion::StringRegionKind: {
+
+ }
+ // Fall-through.
+ case MemRegion::CompoundLiteralRegionKind:
+ case MemRegion::FieldRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ case MemRegion::CXXTempObjectRegionKind:
+ case MemRegion::CXXBaseObjectRegionKind:
+ return UnknownVal();
+
+ case MemRegion::FunctionTextRegionKind:
+ case MemRegion::BlockTextRegionKind:
+ case MemRegion::BlockDataRegionKind:
+ // Technically this can happen if people do funny things with casts.
+ return UnknownVal();
+
+ case MemRegion::CXXThisRegionKind:
+ assert(0 &&
+ "Cannot perform pointer arithmetic on implicit argument 'this'");
+ case MemRegion::GenericMemSpaceRegionKind:
+ case MemRegion::StackLocalsSpaceRegionKind:
+ case MemRegion::StackArgumentsSpaceRegionKind:
+ case MemRegion::HeapSpaceRegionKind:
+ case MemRegion::NonStaticGlobalSpaceRegionKind:
+ case MemRegion::StaticGlobalSpaceRegionKind:
+ case MemRegion::UnknownSpaceRegionKind:
+ assert(0 && "Cannot perform pointer arithmetic on a MemSpace");
+ return UnknownVal();
+ }
+
+ SVal Idx = ER->getIndex();
+ nonloc::ConcreteInt* Base = dyn_cast<nonloc::ConcreteInt>(&Idx);
+
+ // For now, only support:
+ // (a) concrete integer indices that can easily be resolved
+ // (b) 0 + symbolic index
+ if (Base) {
+ if (nonloc::ConcreteInt *Offset = dyn_cast<nonloc::ConcreteInt>(&R)) {
+ // FIXME: Should use SValBuilder here.
+ SVal NewIdx =
+ Base->evalBinOp(svalBuilder, Op,
+ cast<nonloc::ConcreteInt>(svalBuilder.convertToArrayIndex(*Offset)));
+
+ if (!isa<NonLoc>(NewIdx))
+ return UnknownVal();
+
+ const MemRegion* NewER =
+ MRMgr.getElementRegion(ER->getElementType(), cast<NonLoc>(NewIdx),
+ ER->getSuperRegion(), Ctx);
+ return svalBuilder.makeLoc(NewER);
+ }
+ if (0 == Base->getValue()) {
+ const MemRegion* NewER =
+ MRMgr.getElementRegion(ER->getElementType(), R,
+ ER->getSuperRegion(), Ctx);
+ return svalBuilder.makeLoc(NewER);
+ }
+ }
+
+ return UnknownVal();
+}
+
+//===----------------------------------------------------------------------===//
+// Loading values from regions.
+//===----------------------------------------------------------------------===//
+
+Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
+ const MemRegion *R) {
+
+ if (const SVal *V = lookup(B, R, BindingKey::Direct))
+ return *V;
+
+ return Optional<SVal>();
+}
+
+Optional<SVal> RegionStoreManager::getDefaultBinding(RegionBindings B,
+ const MemRegion *R) {
+ if (R->isBoundable())
+ if (const TypedRegion *TR = dyn_cast<TypedRegion>(R))
+ if (TR->getValueType()->isUnionType())
+ return UnknownVal();
+
+ if (const SVal *V = lookup(B, R, BindingKey::Default))
+ return *V;
+
+ return Optional<SVal>();
+}
+
+SVal RegionStoreManager::Retrieve(Store store, Loc L, QualType T) {
+ assert(!isa<UnknownVal>(L) && "location unknown");
+ assert(!isa<UndefinedVal>(L) && "location undefined");
+
+ // For access to concrete addresses, return UnknownVal. Checks
+ // for null dereferences (and similar errors) are done by checkers, not
+ // the Store.
+ // FIXME: We can consider lazily symbolicating such memory, but we really
+ // should defer this when we can reason easily about symbolicating arrays
+ // of bytes.
+ if (isa<loc::ConcreteInt>(L)) {
+ return UnknownVal();
+ }
+ if (!isa<loc::MemRegionVal>(L)) {
+ return UnknownVal();
+ }
+
+ con