aboutsummaryrefslogtreecommitdiff
path: root/lib/Analysis/RegionStore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Analysis/RegionStore.cpp')
-rw-r--r--lib/Analysis/RegionStore.cpp1809
1 files changed, 1088 insertions, 721 deletions
diff --git a/lib/Analysis/RegionStore.cpp b/lib/Analysis/RegionStore.cpp
index 23e8b738b601..3844d6a6149c 100644
--- a/lib/Analysis/RegionStore.cpp
+++ b/lib/Analysis/RegionStore.cpp
@@ -15,9 +15,11 @@
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/MemRegion.h"
+#include "clang/Analysis/PathSensitive/AnalysisContext.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "clang/Analysis/PathSensitive/GRStateTrait.h"
#include "clang/Analysis/Analyses/LiveVariables.h"
+#include "clang/Analysis/Support/Optional.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/ImmutableMap.h"
@@ -27,8 +29,57 @@
using namespace clang;
+#define HEAP_UNDEFINED 0
+#define USE_EXPLICIT_COMPOUND 0
+
+namespace {
+class BindingVal {
+public:
+ enum BindingKind { Direct, Default };
+private:
+ SVal Value;
+ BindingKind Kind;
+
+public:
+ BindingVal(SVal V, BindingKind K) : Value(V), Kind(K) {}
+
+ bool isDefault() const { return Kind == Default; }
+
+ const SVal *getValue() const { return &Value; }
+
+ const SVal *getDirectValue() const { return isDefault() ? 0 : &Value; }
+
+ const SVal *getDefaultValue() const { return isDefault() ? &Value : 0; }
+
+ void Profile(llvm::FoldingSetNodeID& ID) const {
+ Value.Profile(ID);
+ ID.AddInteger(Kind);
+ }
+
+ inline bool operator==(const BindingVal& R) const {
+ return Value == R.Value && Kind == R.Kind;
+ }
+
+ inline bool operator!=(const BindingVal& R) const {
+ return !(*this == R);
+ }
+};
+}
+
+namespace llvm {
+static inline
+llvm::raw_ostream& operator<<(llvm::raw_ostream& os, BindingVal V) {
+ if (V.isDefault())
+ os << "(default) ";
+ else
+ os << "(direct) ";
+ os << *V.getValue();
+ return os;
+}
+} // end llvm namespace
+
// Actual Store type.
-typedef llvm::ImmutableMap<const MemRegion*, SVal> RegionBindingsTy;
+typedef llvm::ImmutableMap<const MemRegion*, BindingVal> RegionBindings;
//===----------------------------------------------------------------------===//
// Fine-grained control of RegionStoreManager.
@@ -36,57 +87,27 @@ typedef llvm::ImmutableMap<const MemRegion*, SVal> RegionBindingsTy;
namespace {
struct VISIBILITY_HIDDEN minimal_features_tag {};
-struct VISIBILITY_HIDDEN maximal_features_tag {};
-
+struct VISIBILITY_HIDDEN maximal_features_tag {};
+
class VISIBILITY_HIDDEN RegionStoreFeatures {
bool SupportsFields;
bool SupportsRemaining;
-
+
public:
RegionStoreFeatures(minimal_features_tag) :
SupportsFields(false), SupportsRemaining(false) {}
-
+
RegionStoreFeatures(maximal_features_tag) :
SupportsFields(true), SupportsRemaining(false) {}
-
+
void enableFields(bool t) { SupportsFields = t; }
-
+
bool supportsFields() const { return SupportsFields; }
bool supportsRemaining() const { return SupportsRemaining; }
};
}
//===----------------------------------------------------------------------===//
-// Region "Views"
-//===----------------------------------------------------------------------===//
-//
-// MemRegions can be layered on top of each other. This GDM entry tracks
-// what are the MemRegions that layer a given MemRegion.
-//
-typedef llvm::ImmutableSet<const MemRegion*> RegionViews;
-namespace { class VISIBILITY_HIDDEN RegionViewMap {}; }
-static int RegionViewMapIndex = 0;
-namespace clang {
- template<> struct GRStateTrait<RegionViewMap>
- : public GRStatePartialTrait<llvm::ImmutableMap<const MemRegion*,
- RegionViews> > {
-
- static void* GDMIndex() { return &RegionViewMapIndex; }
- };
-}
-
-// RegionCasts records the current cast type of a region.
-namespace { class VISIBILITY_HIDDEN RegionCasts {}; }
-static int RegionCastsIndex = 0;
-namespace clang {
- template<> struct GRStateTrait<RegionCasts>
- : public GRStatePartialTrait<llvm::ImmutableMap<const MemRegion*,
- QualType> > {
- static void* GDMIndex() { return &RegionCastsIndex; }
- };
-}
-
-//===----------------------------------------------------------------------===//
// Region "Extents"
//===----------------------------------------------------------------------===//
//
@@ -103,19 +124,15 @@ namespace clang {
}
//===----------------------------------------------------------------------===//
-// Regions with default values.
+// Utility functions.
//===----------------------------------------------------------------------===//
-//
-// This GDM entry tracks what regions have a default value if they have no bound
-// value and have not been killed.
-//
-namespace { class VISIBILITY_HIDDEN RegionDefaultValue {}; }
-static int RegionDefaultValueIndex = 0;
-namespace clang {
- template<> struct GRStateTrait<RegionDefaultValue>
- : public GRStatePartialTrait<llvm::ImmutableMap<const MemRegion*, SVal> > {
- static void* GDMIndex() { return &RegionDefaultValueIndex; }
- };
+
+static bool IsAnyPointerOrIntptr(QualType ty, ASTContext &Ctx) {
+ if (ty->isAnyPointerType())
+ return true;
+
+ return ty->isIntegerType() && ty->isScalarType() &&
+ Ctx.getTypeSize(ty) == Ctx.getTypeSize(Ctx.VoidPtrTy);
}
//===----------------------------------------------------------------------===//
@@ -125,87 +142,104 @@ namespace clang {
namespace {
class VISIBILITY_HIDDEN RegionStoreSubRegionMap : public SubRegionMap {
- typedef llvm::DenseMap<const MemRegion*,
- llvm::ImmutableSet<const MemRegion*> > Map;
-
- llvm::ImmutableSet<const MemRegion*>::Factory F;
+ typedef llvm::ImmutableSet<const MemRegion*> SetTy;
+ typedef llvm::DenseMap<const MemRegion*, SetTy> Map;
+ SetTy::Factory F;
Map M;
-
public:
- void add(const MemRegion* Parent, const MemRegion* SubRegion) {
+ bool add(const MemRegion* Parent, const MemRegion* SubRegion) {
Map::iterator I = M.find(Parent);
- M.insert(std::make_pair(Parent,
- F.Add(I == M.end() ? F.GetEmptySet() : I->second, SubRegion)));
+
+ 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() {}
-
+
bool iterSubRegions(const MemRegion* Parent, Visitor& V) const {
Map::iterator I = M.find(Parent);
if (I == M.end())
return true;
-
+
llvm::ImmutableSet<const MemRegion*> S = I->second;
for (llvm::ImmutableSet<const MemRegion*>::iterator SI=S.begin(),SE=S.end();
SI != SE; ++SI) {
if (!V.Visit(Parent, *SI))
return false;
}
-
+
return true;
}
-};
+
+ typedef SetTy::iterator iterator;
+
+ std::pair<iterator, iterator> begin_end(const MemRegion *R) {
+ Map::iterator I = M.find(R);
+ SetTy S = I == M.end() ? F.GetEmptySet() : I->second;
+ return std::make_pair(S.begin(), S.end());
+ }
+};
class VISIBILITY_HIDDEN RegionStoreManager : public StoreManager {
const RegionStoreFeatures Features;
- RegionBindingsTy::Factory RBFactory;
- RegionViews::Factory RVFactory;
-
- const MemRegion* SelfRegion;
- const ImplicitParamDecl *SelfDecl;
+ RegionBindings::Factory RBFactory;
+
+ typedef llvm::DenseMap<const GRState *, RegionStoreSubRegionMap*> SMCache;
+ SMCache SC;
public:
- RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f)
+ RegionStoreManager(GRStateManager& mgr, const RegionStoreFeatures &f)
: StoreManager(mgr),
Features(f),
- RBFactory(mgr.getAllocator()),
- RVFactory(mgr.getAllocator()),
- SelfRegion(0), SelfDecl(0) {
- if (const ObjCMethodDecl* MD =
- dyn_cast<ObjCMethodDecl>(&StateMgr.getCodeDecl()))
- SelfDecl = MD->getSelfDecl();
+ RBFactory(mgr.getAllocator()) {}
+
+ virtual ~RegionStoreManager() {
+ for (SMCache::iterator I = SC.begin(), E = SC.end(); I != E; ++I)
+ delete (*I).second;
}
- virtual ~RegionStoreManager() {}
+ SubRegionMap *getSubRegionMap(const GRState *state);
+
+ RegionStoreSubRegionMap *getRegionStoreSubRegionMap(Store store);
+
+ Optional<SVal> getBinding(RegionBindings B, const MemRegion *R);
+ 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);
- SubRegionMap* getSubRegionMap(const GRState *state);
-
/// getLValueString - Returns an SVal representing the lvalue of a
/// StringLiteral. Within RegionStore a StringLiteral has an
/// associated StringRegion, and the lvalue of a StringLiteral is
/// the lvalue of that region.
- SVal getLValueString(const GRState *state, const StringLiteral* S);
+ SVal getLValueString(const StringLiteral* S);
/// getLValueCompoundLiteral - Returns an SVal representing the
/// lvalue of a compound literal. Within RegionStore a compound
/// literal has an associated region, and the lvalue of the
/// compound literal is the lvalue of that region.
- SVal getLValueCompoundLiteral(const GRState *state, const CompoundLiteralExpr*);
+ SVal getLValueCompoundLiteral(const CompoundLiteralExpr*);
/// getLValueVar - Returns an SVal that represents the lvalue of a
/// variable. Within RegionStore a variable has an associated
/// VarRegion, and the lvalue of the variable is the lvalue of that region.
- SVal getLValueVar(const GRState *state, const VarDecl* VD);
-
- SVal getLValueIvar(const GRState *state, const ObjCIvarDecl* D, SVal Base);
+ SVal getLValueVar(const VarDecl *VD, const LocationContext *LC);
- SVal getLValueField(const GRState *state, SVal Base, const FieldDecl* D);
-
- SVal getLValueFieldOrIvar(const GRState *state, SVal Base, const Decl* D);
+ SVal getLValueIvar(const ObjCIvarDecl* D, SVal Base);
+
+ SVal getLValueField(const FieldDecl* D, SVal Base);
- SVal getLValueElement(const GRState *state, QualType elementType,
- SVal Base, SVal Offset);
+ SVal getLValueFieldOrIvar(const Decl* D, SVal Base);
+
+ SVal getLValueElement(QualType elementType, SVal Offset, SVal Base);
/// ArrayToPointer - Emulates the "decay" of an array to a pointer
@@ -216,61 +250,52 @@ public:
/// casts from arrays to pointers.
SVal ArrayToPointer(Loc Array);
- CastResult CastRegion(const GRState *state, const MemRegion* R,
- QualType CastToTy);
-
SVal EvalBinOp(const GRState *state, BinaryOperator::Opcode Op,Loc L,
NonLoc R, QualType resultTy);
- Store getInitialStore() { return RBFactory.GetEmptyMap().getRoot(); }
-
- /// getSelfRegion - Returns the region for the 'self' (Objective-C) or
- /// 'this' object (C++). When used when analyzing a normal function this
- /// method returns NULL.
- const MemRegion* getSelfRegion(Store) {
- if (!SelfDecl)
- return 0;
-
- if (!SelfRegion) {
- const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(&StateMgr.getCodeDecl());
- SelfRegion = MRMgr.getObjCObjectRegion(MD->getClassInterface(),
- MRMgr.getHeapRegion());
- }
-
- return SelfRegion;
+ Store getInitialStore(const LocationContext *InitLoc) {
+ return RBFactory.GetEmptyMap().getRoot();
}
-
+
//===-------------------------------------------------------------------===//
// Binding values to regions.
//===-------------------------------------------------------------------===//
+ const GRState *InvalidateRegion(const GRState *state, const MemRegion *R,
+ const Expr *E, unsigned Count);
+
+private:
+ void RemoveSubRegionBindings(RegionBindings &B, const MemRegion *R,
+ RegionStoreSubRegionMap &M);
+
+public:
const GRState *Bind(const GRState *state, Loc LV, SVal V);
const GRState *BindCompoundLiteral(const GRState *state,
- const CompoundLiteralExpr* CL, SVal V);
-
- const GRState *BindDecl(const GRState *state, const VarDecl* VD, SVal InitVal);
+ const CompoundLiteralExpr* CL, SVal V);
+
+ const GRState *BindDecl(const GRState *ST, const VarDecl *VD,
+ const LocationContext *LC, SVal InitVal);
- const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl* VD) {
+ const GRState *BindDeclWithNoInit(const GRState *state, const VarDecl*,
+ const LocationContext *) {
return state;
}
/// BindStruct - Bind a compound value to a structure.
const GRState *BindStruct(const GRState *, const TypedRegion* R, SVal V);
-
+
const GRState *BindArray(const GRState *state, const TypedRegion* R, SVal V);
-
- /// KillStruct - Set the entire struct to unknown.
- const GRState *KillStruct(const GRState *state, const TypedRegion* R);
- const GRState *setDefaultValue(const GRState *state, const MemRegion* R, SVal V);
+ /// KillStruct - Set the entire struct to unknown.
+ Store KillStruct(Store store, const TypedRegion* R);
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
@@ -282,55 +307,66 @@ public:
/// return undefined
/// else
/// return symbolic
- SVal Retrieve(const GRState *state, Loc L, QualType T = QualType());
+ SValuator::CastResult Retrieve(const GRState *state, Loc L,
+ QualType T = QualType());
+
+ SVal RetrieveElement(const GRState *state, const ElementRegion *R);
+
+ SVal RetrieveField(const GRState *state, const FieldRegion *R);
+
+ SVal RetrieveObjCIvar(const GRState *state, const ObjCIvarRegion *R);
- SVal RetrieveElement(const GRState* state, const ElementRegion* R);
+ SVal RetrieveVar(const GRState *state, const VarRegion *R);
- SVal RetrieveField(const GRState* state, const FieldRegion* R);
+ SVal RetrieveLazySymbol(const GRState *state, const TypedRegion *R);
+
+ SVal RetrieveFieldOrElementCommon(const GRState *state, 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;
+ /// struct copy:
+ /// struct s x, y;
/// x = y;
/// y's value is retrieved by this method.
SVal RetrieveStruct(const GRState *St, const TypedRegion* R);
-
+
SVal RetrieveArray(const GRState *St, const TypedRegion* R);
+ std::pair<const GRState*, const MemRegion*>
+ GetLazyBinding(RegionBindings B, const MemRegion *R);
+
+ const GRState* CopyLazyBindings(nonloc::LazyCompoundVal V,
+ const GRState *state,
+ const TypedRegion *R);
+
+ const ElementRegion *GetElementZeroRegion(const SymbolicRegion *SR,
+ QualType T);
+
//===------------------------------------------------------------------===//
// State pruning.
//===------------------------------------------------------------------===//
-
+
/// RemoveDeadBindings - Scans the RegionStore of 'state' for dead values.
/// It returns a new Store with these values removed.
- Store RemoveDeadBindings(const GRState *state, Stmt* Loc, SymbolReaper& SymReaper,
+ void RemoveDeadBindings(GRState &state, Stmt* Loc, SymbolReaper& SymReaper,
llvm::SmallVectorImpl<const MemRegion*>& RegionRoots);
+ const GRState *EnterStackFrame(const GRState *state,
+ const StackFrameContext *frame);
+
//===------------------------------------------------------------------===//
// Region "extents".
//===------------------------------------------------------------------===//
-
+
const GRState *setExtent(const GRState *state, const MemRegion* R, SVal Extent);
SVal getSizeInElements(const GRState *state, const MemRegion* R);
//===------------------------------------------------------------------===//
- // Region "views".
- //===------------------------------------------------------------------===//
-
- const GRState *AddRegionView(const GRState *state, const MemRegion* View,
- const MemRegion* Base);
-
- const GRState *RemoveRegionView(const GRState *state, const MemRegion* View,
- const MemRegion* Base);
-
- //===------------------------------------------------------------------===//
// Utility methods.
//===------------------------------------------------------------------===//
-
- const GRState *setCastType(const GRState *state, const MemRegion* R, QualType T);
- static inline RegionBindingsTy GetRegionBindings(Store store) {
- return RegionBindingsTy(static_cast<const RegionBindingsTy::TreeTy*>(store));
+ 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,
@@ -344,7 +380,7 @@ public:
BasicValueFactory& getBasicVals() {
return StateMgr.getBasicVals();
}
-
+
// FIXME: Remove.
ASTContext& getContext() { return StateMgr.getContext(); }
};
@@ -366,18 +402,155 @@ StoreManager *clang::CreateFieldsOnlyRegionStoreManager(GRStateManager &StMgr) {
return new RegionStoreManager(StMgr, F);
}
-SubRegionMap* RegionStoreManager::getSubRegionMap(const GRState *state) {
- RegionBindingsTy B = GetRegionBindings(state->getStore());
+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);
+}
+
+RegionStoreSubRegionMap*
+RegionStoreManager::getRegionStoreSubRegionMap(Store store) {
+ RegionBindings B = GetRegionBindings(store);
RegionStoreSubRegionMap *M = new RegionStoreSubRegionMap();
-
- for (RegionBindingsTy::iterator I=B.begin(), E=B.end(); I!=E; ++I) {
- if (const SubRegion* R = dyn_cast<SubRegion>(I.getKey()))
- M->add(R->getSuperRegion(), R);
+
+ 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()))
+ 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;
}
+SubRegionMap *RegionStoreManager::getSubRegionMap(const GRState *state) {
+ return getRegionStoreSubRegionMap(state->getStore());
+}
+
+//===----------------------------------------------------------------------===//
+// Binding invalidation.
+//===----------------------------------------------------------------------===//
+
+void RegionStoreManager::RemoveSubRegionBindings(RegionBindings &B,
+ const MemRegion *R,
+ RegionStoreSubRegionMap &M) {
+ RegionStoreSubRegionMap::iterator I, E;
+
+ for (llvm::tie(I, E) = M.begin_end(R); I != E; ++I)
+ RemoveSubRegionBindings(B, *I, M);
+
+ B = RBFactory.Remove(B, R);
+}
+
+const GRState *RegionStoreManager::InvalidateRegion(const GRState *state,
+ const MemRegion *R,
+ const Expr *Ex,
+ unsigned Count) {
+ ASTContext& Ctx = StateMgr.getContext();
+
+ // Strip away casts.
+ R = R->getBaseRegion();
+
+ // Get the mapping of regions -> subregions.
+ llvm::OwningPtr<RegionStoreSubRegionMap>
+ SubRegions(getRegionStoreSubRegionMap(state->getStore()));
+
+ RegionBindings B = GetRegionBindings(state->getStore());
+
+ llvm::DenseMap<const MemRegion *, unsigned> Visited;
+ llvm::SmallVector<const MemRegion *, 10> WorkList;
+ WorkList.push_back(R);
+
+ while (!WorkList.empty()) {
+ R = WorkList.back();
+ WorkList.pop_back();
+
+ // Have we visited this region before?
+ unsigned &visited = Visited[R];
+ if (visited)
+ continue;
+ visited = 1;
+
+ // Add subregions to work list.
+ RegionStoreSubRegionMap::iterator I, E;
+ for (llvm::tie(I, E) = SubRegions->begin_end(R); I!=E; ++I)
+ WorkList.push_back(*I);
+
+ // Get the old binding. Is it a region? If so, add it to the worklist.
+ if (Optional<SVal> V = getDirectBinding(B, R)) {
+ if (const MemRegion *RV = V->getAsRegion())
+ WorkList.push_back(RV);
+ }
+
+ // Handle region.
+ if (isa<AllocaRegion>(R) || isa<SymbolicRegion>(R) ||
+ isa<ObjCObjectRegion>(R)) {
+ // Invalidate the region by setting its default value to
+ // conjured symbol. The type of the symbol is irrelavant.
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+ Count);
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ continue;
+ }
+
+ if (!R->isBoundable())
+ continue;
+
+ const TypedRegion *TR = cast<TypedRegion>(R);
+ QualType T = TR->getValueType(Ctx);
+
+ if (const RecordType *RT = T->getAsStructureType()) {
+ const RecordDecl *RD = RT->getDecl()->getDefinition(Ctx);
+
+ // No record definition. There is nothing we can do.
+ if (!RD)
+ continue;
+
+ // Invalidate the region by setting its default value to
+ // conjured symbol. The type of the symbol is irrelavant.
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, Ctx.IntTy,
+ Count);
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ continue;
+ }
+
+ if (const ArrayType *AT = Ctx.getAsArrayType(T)) {
+ // Set the default value of the array to conjured symbol.
+ DefinedOrUnknownSVal V =
+ ValMgr.getConjuredSymbolVal(R, Ex, AT->getElementType(), Count);
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ continue;
+ }
+
+ if ((isa<FieldRegion>(R)||isa<ElementRegion>(R)||isa<ObjCIvarRegion>(R))
+ && Visited[cast<SubRegion>(R)->getSuperRegion()]) {
+ // For fields and elements whose super region has also been invalidated,
+ // only remove the old binding. The super region will get set with a
+ // default value from which we can lazily derive a new symbolic value.
+ B = RBFactory.Remove(B, R);
+ continue;
+ }
+
+ // Invalidate the binding.
+ DefinedOrUnknownSVal V = ValMgr.getConjuredSymbolVal(R, Ex, T, Count);
+ assert(SymbolManager::canSymbolicate(T) || V.isUnknown());
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct));
+ }
+
+ // Create a new state with the updated bindings.
+ return state->makeWithStore(B.getRoot());
+}
+
//===----------------------------------------------------------------------===//
// getLValueXXX methods.
//===----------------------------------------------------------------------===//
@@ -386,40 +559,36 @@ SubRegionMap* RegionStoreManager::getSubRegionMap(const GRState *state) {
/// StringLiteral. Within RegionStore a StringLiteral has an
/// associated StringRegion, and the lvalue of a StringLiteral is the
/// lvalue of that region.
-SVal RegionStoreManager::getLValueString(const GRState *St,
- const StringLiteral* S) {
+SVal RegionStoreManager::getLValueString(const StringLiteral* S) {
return loc::MemRegionVal(MRMgr.getStringRegion(S));
}
/// getLValueVar - Returns an SVal that represents the lvalue of a
/// variable. Within RegionStore a variable has an associated
/// VarRegion, and the lvalue of the variable is the lvalue of that region.
-SVal RegionStoreManager::getLValueVar(const GRState *St, const VarDecl* VD) {
- return loc::MemRegionVal(MRMgr.getVarRegion(VD));
+SVal RegionStoreManager::getLValueVar(const VarDecl *VD,
+ const LocationContext *LC) {
+ return loc::MemRegionVal(MRMgr.getVarRegion(VD, LC));
}
/// getLValueCompoundLiteral - Returns an SVal representing the lvalue
/// of a compound literal. Within RegionStore a compound literal
/// has an associated region, and the lvalue of the compound literal
/// is the lvalue of that region.
-SVal
-RegionStoreManager::getLValueCompoundLiteral(const GRState *St,
- const CompoundLiteralExpr* CL) {
+SVal
+RegionStoreManager::getLValueCompoundLiteral(const CompoundLiteralExpr* CL) {
return loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL));
}
-SVal RegionStoreManager::getLValueIvar(const GRState *St, const ObjCIvarDecl* D,
- SVal Base) {
- return getLValueFieldOrIvar(St, Base, D);
+SVal RegionStoreManager::getLValueIvar(const ObjCIvarDecl* D, SVal Base) {
+ return getLValueFieldOrIvar(D, Base);
}
-SVal RegionStoreManager::getLValueField(const GRState *St, SVal Base,
- const FieldDecl* D) {
- return getLValueFieldOrIvar(St, Base, D);
+SVal RegionStoreManager::getLValueField(const FieldDecl* D, SVal Base) {
+ return getLValueFieldOrIvar(D, Base);
}
-SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base,
- const Decl* D) {
+SVal RegionStoreManager::getLValueFieldOrIvar(const Decl* D, SVal Base) {
if (Base.isUnknownOrUndef())
return Base;
@@ -446,7 +615,7 @@ SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base,
assert(0 && "Unhandled Base.");
return Base;
}
-
+
// NOTE: We must have this check first because ObjCIvarDecl is a subclass
// of FieldDecl.
if (const ObjCIvarDecl *ID = dyn_cast<ObjCIvarDecl>(D))
@@ -455,9 +624,8 @@ SVal RegionStoreManager::getLValueFieldOrIvar(const GRState *St, SVal Base,
return loc::MemRegionVal(MRMgr.getFieldRegion(cast<FieldDecl>(D), BaseR));
}
-SVal RegionStoreManager::getLValueElement(const GRState *St,
- QualType elementType,
- SVal Base, SVal Offset) {
+SVal RegionStoreManager::getLValueElement(QualType elementType, SVal Offset,
+ SVal Base) {
// If the base is an unknown or undefined value, just return it back.
// FIXME: For absolute pointer addresses, we just return that value back as
@@ -474,7 +642,10 @@ SVal RegionStoreManager::getLValueElement(const GRState *St,
// Pointer of any type can be cast and used as array base.
const ElementRegion *ElemR = dyn_cast<ElementRegion>(BaseRegion);
-
+
+ // Convert the offset to the appropriate size and signedness.
+ Offset = ValMgr.convertToArrayIndex(Offset);
+
if (!ElemR) {
//
// If the base region is not an ElementRegion, create one.
@@ -485,54 +656,26 @@ SVal RegionStoreManager::getLValueElement(const GRState *St,
//
// Observe that 'p' binds to an AllocaRegion.
//
-
- // Offset might be unsigned. We have to convert it to signed ConcreteInt.
- if (nonloc::ConcreteInt* CI = dyn_cast<nonloc::ConcreteInt>(&Offset)) {
- const llvm::APSInt& OffI = CI->getValue();
- if (OffI.isUnsigned()) {
- llvm::APSInt Tmp = OffI;
- Tmp.setIsSigned(true);
- Offset = ValMgr.makeIntVal(Tmp);
- }
- }
return loc::MemRegionVal(MRMgr.getElementRegion(elementType, Offset,
BaseRegion, getContext()));
}
-
+
SVal BaseIdx = ElemR->getIndex();
-
+
if (!isa<nonloc::ConcreteInt>(BaseIdx))
return UnknownVal();
-
+
const llvm::APSInt& BaseIdxI = cast<nonloc::ConcreteInt>(BaseIdx).getValue();
const llvm::APSInt& OffI = cast<nonloc::ConcreteInt>(Offset).getValue();
assert(BaseIdxI.isSigned());
-
- // FIXME: This appears to be the assumption of this code. We should review
- // whether or not BaseIdxI.getBitWidth() < OffI.getBitWidth(). If it
- // can't we need to put a comment here. If it can, we should handle it.
- assert(BaseIdxI.getBitWidth() >= OffI.getBitWidth());
- const MemRegion *ArrayR = ElemR->getSuperRegion();
- SVal NewIdx;
-
- if (OffI.isUnsigned() || OffI.getBitWidth() < BaseIdxI.getBitWidth()) {
- // 'Offset' might be unsigned. We have to convert it to signed and
- // possibly extend it.
- llvm::APSInt Tmp = OffI;
-
- if (OffI.getBitWidth() < BaseIdxI.getBitWidth())
- Tmp.extend(BaseIdxI.getBitWidth());
-
- Tmp.setIsSigned(true);
- Tmp += BaseIdxI; // Compute the new offset.
- NewIdx = ValMgr.makeIntVal(Tmp);
- }
- else
- NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI));
+ // Compute the new index.
+ SVal NewIdx = nonloc::ConcreteInt(getBasicVals().getValue(BaseIdxI + OffI));
+ // Construct the new ElementRegion.
+ const MemRegion *ArrayR = ElemR->getSuperRegion();
return loc::MemRegionVal(MRMgr.getElementRegion(elementType, NewIdx, ArrayR,
- getContext()));
+ getContext()));
}
//===----------------------------------------------------------------------===//
@@ -540,64 +683,62 @@ SVal RegionStoreManager::getLValueElement(const GRState *St,
//===----------------------------------------------------------------------===//
SVal RegionStoreManager::getSizeInElements(const GRState *state,
- const MemRegion* R) {
- if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
- // Get the type of the variable.
- QualType T = VR->getDesugaredValueType(getContext());
+ const MemRegion *R) {
- // FIXME: Handle variable-length arrays.
- if (isa<VariableArrayType>(T))
+ switch (R->getKind()) {
+ case MemRegion::MemSpaceRegionKind:
+ assert(0 && "Cannot index into a MemSpace");
return UnknownVal();
-
- if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(T)) {
- // return the size as signed integer.
- return ValMgr.makeIntVal(CAT->getSize(), false);
- }
- const QualType* CastTy = state->get<RegionCasts>(VR);
-
- // If the VarRegion is cast to other type, compute the size with respect to
- // that type.
- if (CastTy) {
- QualType EleTy =cast<PointerType>(CastTy->getTypePtr())->getPointeeType();
- QualType VarTy = VR->getValueType(getContext());
- uint64_t EleSize = getContext().getTypeSize(EleTy);
- uint64_t VarSize = getContext().getTypeSize(VarTy);
- assert(VarSize != 0);
- return ValMgr.makeIntVal(VarSize/EleSize, false);
- }
+ case MemRegion::CodeTextRegionKind:
+ // Technically this can happen if people do funny things with casts.
+ return UnknownVal();
- // Clients can use ordinary variables as if they were arrays. These
- // essentially are arrays of size 1.
- return ValMgr.makeIntVal(1, false);
- }
+ // Not yet handled.
+ case MemRegion::AllocaRegionKind:
+ case MemRegion::CompoundLiteralRegionKind:
+ case MemRegion::ElementRegionKind:
+ case MemRegion::FieldRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ case MemRegion::ObjCObjectRegionKind:
+ case MemRegion::SymbolicRegionKind:
+ return UnknownVal();
- if (const StringRegion* SR = dyn_cast<StringRegion>(R)) {
- const StringLiteral* Str = SR->getStringLiteral();
- // We intentionally made the size value signed because it participates in
- // operations with signed indices.
- return ValMgr.makeIntVal(Str->getByteLength()+1, false);
- }
+ case MemRegion::StringRegionKind: {
+ const StringLiteral* Str = cast<StringRegion>(R)->getStringLiteral();
+ // We intentionally made the size value signed because it participates in
+ // operations with signed indices.
+ return ValMgr.makeIntVal(Str->getByteLength()+1, false);
+ }
- if (const FieldRegion* FR = dyn_cast<FieldRegion>(R)) {
- // FIXME: Unsupported yet.
- FR = 0;
- return UnknownVal();
- }
+ case MemRegion::VarRegionKind: {
+ const VarRegion* VR = cast<VarRegion>(R);
+ // Get the type of the variable.
+ QualType T = VR->getDesugaredValueType(getContext());
- if (isa<SymbolicRegion>(R)) {
- return UnknownVal();
- }
+ // FIXME: Handle variable-length arrays.
+ if (isa<VariableArrayType>(T))
+ return UnknownVal();
- if (isa<AllocaRegion>(R)) {
- return UnknownVal();
- }
+ if (const ConstantArrayType* CAT = dyn_cast<ConstantArrayType>(T)) {
+ // return the size as signed integer.
+ return ValMgr.makeIntVal(CAT->getSize(), false);
+ }
- if (isa<ElementRegion>(R)) {
- return UnknownVal();
+ // Clients can use ordinary variables as if they were arrays. These
+ // essentially are arrays of size 1.
+ return ValMgr.makeIntVal(1, false);
+ }
+
+ case MemRegion::BEG_DECL_REGIONS:
+ case MemRegion::END_DECL_REGIONS:
+ case MemRegion::BEG_TYPED_REGIONS:
+ case MemRegion::END_TYPED_REGIONS:
+ assert(0 && "Infeasible region");
+ return UnknownVal();
}
- assert(0 && "Other regions are not supported yet.");
+ assert(0 && "Unreachable");
return UnknownVal();
}
@@ -620,105 +761,29 @@ const GRState *RegionStoreManager::setExtent(const GRState *state,
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(getContext())->getDesugaredType();
+ QualType T = ArrayR->getValueType(getContext()).getDesugaredType();
ArrayType *AT = cast<ArrayType>(T);
T = AT->getElementType();
-
- nonloc::ConcreteInt Idx(getBasicVals().getZeroWithPtrWidth(false));
- ElementRegion* ER = MRMgr.getElementRegion(T, Idx, ArrayR, getContext());
-
- return loc::MemRegionVal(ER);
-}
-
-RegionStoreManager::CastResult
-RegionStoreManager::CastRegion(const GRState *state, const MemRegion* R,
- QualType CastToTy) {
-
- ASTContext& Ctx = StateMgr.getContext();
-
- // We need to know the real type of CastToTy.
- QualType ToTy = Ctx.getCanonicalType(CastToTy);
-
- // Check cast to ObjCQualifiedID type.
- if (ToTy->isObjCQualifiedIdType()) {
- // FIXME: Record the type information aside.
- return CastResult(state, R);
- }
-
- // CodeTextRegion should be cast to only function pointer type.
- if (isa<CodeTextRegion>(R)) {
- assert(CastToTy->isFunctionPointerType() || CastToTy->isBlockPointerType()
- || (CastToTy->isPointerType()
- && CastToTy->getAsPointerType()->getPointeeType()->isVoidType()));
- return CastResult(state, R);
- }
-
- // Now assume we are casting from pointer to pointer. Other cases should
- // already be handled.
- QualType PointeeTy = cast<PointerType>(ToTy.getTypePtr())->getPointeeType();
-
- // Process region cast according to the kind of the region being cast.
-
- // FIXME: Need to handle arbitrary downcasts.
- if (isa<SymbolicRegion>(R) || isa<AllocaRegion>(R)) {
- state = setCastType(state, R, ToTy);
- return CastResult(state, R);
- }
-
- // VarRegion, ElementRegion, and FieldRegion has an inherent type. Normally
- // they should not be cast. We only layer an ElementRegion when the cast-to
- // pointee type is of smaller size. In other cases, we return the original
- // VarRegion.
- if (isa<VarRegion>(R) || isa<ElementRegion>(R) || isa<FieldRegion>(R)
- || isa<ObjCIvarRegion>(R) || isa<CompoundLiteralRegion>(R)) {
- // If the pointee type is incomplete, do not compute its size, and return
- // the original region.
- if (const RecordType *RT = dyn_cast<RecordType>(PointeeTy.getTypePtr())) {
- const RecordDecl *D = RT->getDecl();
- if (!D->getDefinition(getContext()))
- return CastResult(state, R);
- }
-
- QualType ObjTy = cast<TypedRegion>(R)->getValueType(getContext());
- uint64_t PointeeTySize = getContext().getTypeSize(PointeeTy);
- uint64_t ObjTySize = getContext().getTypeSize(ObjTy);
-
- if ((PointeeTySize > 0 && PointeeTySize < ObjTySize) ||
- (ObjTy->isAggregateType() && PointeeTy->isScalarType()) ||
- ObjTySize == 0 /* R has 'void*' type. */) {
- // Record the cast type of the region.
- state = setCastType(state, R, ToTy);
-
- SVal Idx = ValMgr.makeZeroArrayIndex();
- ElementRegion* ER = MRMgr.getElementRegion(PointeeTy, Idx,R,getContext());
- return CastResult(state, ER);
- } else {
- state = setCastType(state, R, ToTy);
- return CastResult(state, R);
- }
- }
- if (isa<ObjCObjectRegion>(R)) {
- return CastResult(state, R);
- }
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ ElementRegion* ER = MRMgr.getElementRegion(T, ZeroIdx, ArrayR, getContext());
- assert(0 && "Unprocessed region.");
- return 0;
+ return loc::MemRegionVal(ER);
}
//===----------------------------------------------------------------------===//
// Pointer arithmetic.
//===----------------------------------------------------------------------===//
-SVal RegionStoreManager::EvalBinOp(const GRState *state,
+SVal RegionStoreManager::EvalBinOp(const GRState *state,
BinaryOperator::Opcode Op, Loc L, NonLoc R,
QualType resultTy) {
// Assume the base location is MemRegionVal.
@@ -728,64 +793,89 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
const MemRegion* MR = cast<loc::MemRegionVal>(L).getRegion();
const ElementRegion *ER = 0;
- // If the operand is a symbolic or alloca region, create the first element
- // region on it.
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR)) {
- QualType T;
- // If the SymbolicRegion was cast to another type, use that type.
- if (const QualType *t = state->get<RegionCasts>(SR)) {
- T = *t;
- } else {
- // Otherwise use the symbol's type.
+ switch (MR->getKind()) {
+ case MemRegion::SymbolicRegionKind: {
+ const SymbolicRegion *SR = cast<SymbolicRegion>(MR);
SymbolRef Sym = SR->getSymbol();
- T = Sym->getType(getContext());
+ QualType T = Sym->getType(getContext());
+ QualType EleTy;
+
+ if (const PointerType *PT = T->getAs<PointerType>())
+ EleTy = PT->getPointeeType();
+ else
+ EleTy = T->getAs<ObjCObjectPointerType>()->getPointeeType();
+
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, getContext());
+ break;
+ }
+ case MemRegion::AllocaRegionKind: {
+ const AllocaRegion *AR = cast<AllocaRegion>(MR);
+ QualType T = getContext().CharTy; // Create an ElementRegion of bytes.
+ QualType EleTy = T->getAs<PointerType>()->getPointeeType();
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, getContext());
+ break;
}
- QualType EleTy = T->getAsPointerType()->getPointeeType();
- SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
- ER = MRMgr.getElementRegion(EleTy, ZeroIdx, SR, getContext());
- }
- else if (const AllocaRegion *AR = dyn_cast<AllocaRegion>(MR)) {
- // Get the alloca region's current cast type.
+ 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::ObjCObjectRegionKind:
+ case MemRegion::ObjCIvarRegionKind:
+ return UnknownVal();
- GRStateTrait<RegionCasts>::lookup_type T = state->get<RegionCasts>(AR);
- assert(T && "alloca region has no type.");
- QualType EleTy = cast<PointerType>(T->getTypePtr())->getPointeeType();
- SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
- ER = MRMgr.getElementRegion(EleTy, ZeroIdx, AR, getContext());
- }
- else if (isa<FieldRegion>(MR)) {
- // Not track pointer arithmetic on struct fields.
- return UnknownVal();
- }
- else {
- ER = cast<ElementRegion>(MR);
+ case MemRegion::CodeTextRegionKind:
+ // Technically this can happen if people do funny things with casts.
+ return UnknownVal();
+
+ case MemRegion::MemSpaceRegionKind:
+ assert(0 && "Cannot perform pointer arithmetic on a MemSpace");
+ return UnknownVal();
+
+ case MemRegion::BEG_DECL_REGIONS:
+ case MemRegion::END_DECL_REGIONS:
+ case MemRegion::BEG_TYPED_REGIONS:
+ case MemRegion::END_TYPED_REGIONS:
+ assert(0 && "Infeasible region");
+ return UnknownVal();
}
SVal Idx = ER->getIndex();
-
nonloc::ConcreteInt* Base = dyn_cast<nonloc::ConcreteInt>(&Idx);
- nonloc::ConcreteInt* Offset = dyn_cast<nonloc::ConcreteInt>(&R);
-
- // Only support concrete integer indexes for now.
- if (Base && Offset) {
- // FIXME: For now, convert the signedness and bitwidth of offset in case
- // they don't match. This can result from pointer arithmetic. In reality,
- // we should figure out what are the proper semantics and implement them.
- //
- // This addresses the test case test/Analysis/ptr-arith.c
- //
- nonloc::ConcreteInt OffConverted(getBasicVals().Convert(Base->getValue(),
- Offset->getValue()));
- SVal NewIdx = Base->evalBinOp(ValMgr, Op, OffConverted);
- const MemRegion* NewER =
- MRMgr.getElementRegion(ER->getElementType(), NewIdx,ER->getSuperRegion(),
- getContext());
- return ValMgr.makeLoc(NewER);
+ // 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 SValuator here.
+ SVal NewIdx =
+ Base->evalBinOp(ValMgr, Op,
+ cast<nonloc::ConcreteInt>(ValMgr.convertToArrayIndex(*Offset)));
+ const MemRegion* NewER =
+ MRMgr.getElementRegion(ER->getElementType(), NewIdx,
+ ER->getSuperRegion(), getContext());
+ return ValMgr.makeLoc(NewER);
+ }
+ if (0 == Base->getValue()) {
+ const MemRegion* NewER =
+ MRMgr.getElementRegion(ER->getElementType(), R,
+ ER->getSuperRegion(), getContext());
+ return ValMgr.makeLoc(NewER);
+ }
}
-
+
return UnknownVal();
}
@@ -793,7 +883,71 @@ SVal RegionStoreManager::EvalBinOp(const GRState *state,
// Loading values from regions.
//===----------------------------------------------------------------------===//
-SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
+Optional<SVal> RegionStoreManager::getDirectBinding(RegionBindings B,
+ const MemRegion *R) {
+ if (const BindingVal *BV = B.lookup(R))
+ return Optional<SVal>::create(BV->getDirectValue());
+
+ 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(getContext())->isUnionType())
+ return UnknownVal();
+
+ if (BindingVal const *V = B.lookup(R))
+ return Optional<SVal>::create(V->getDefaultValue());
+
+ return Optional<SVal>();
+}
+
+Optional<SVal> RegionStoreManager::getBinding(RegionBindings B,
+ const MemRegion *R) {
+ if (const BindingVal *BV = B.lookup(R))
+ return Optional<SVal>::create(BV->getValue());
+
+ return Optional<SVal>();
+}
+
+static bool IsReinterpreted(QualType RTy, QualType UsedTy, ASTContext &Ctx) {
+ RTy = Ctx.getCanonicalType(RTy);
+ UsedTy = Ctx.getCanonicalType(UsedTy);
+
+ if (RTy == UsedTy)
+ return false;
+
+
+ // Recursively check the types. We basically want to see if a pointer value
+ // is ever reinterpreted as a non-pointer, e.g. void** and intptr_t*
+ // represents a reinterpretation.
+ if (Loc::IsLocType(RTy) && Loc::IsLocType(UsedTy)) {
+ const PointerType *PRTy = RTy->getAs<PointerType>();
+ const PointerType *PUsedTy = UsedTy->getAs<PointerType>();
+
+ return PUsedTy && PRTy &&
+ IsReinterpreted(PRTy->getPointeeType(),
+ PUsedTy->getPointeeType(), Ctx);
+ }
+
+ return true;
+}
+
+const ElementRegion *
+RegionStoreManager::GetElementZeroRegion(const SymbolicRegion *SR, QualType T) {
+ ASTContext &Ctx = getContext();
+ SVal idx = ValMgr.makeZeroArrayIndex();
+ assert(!T.isNull());
+ return MRMgr.getElementRegion(T, idx, SR, Ctx);
+}
+
+
+
+SValuator::CastResult
+RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
@@ -801,7 +955,7 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// FIXME: Is this even possible? Shouldn't this be treated as a null
// dereference at a higher level?
if (isa<loc::ConcreteInt>(L))
- return UndefinedVal();
+ return SValuator::CastResult(state, UndefinedVal());
const MemRegion *MR = cast<loc::MemRegionVal>(L).getRegion();
@@ -811,13 +965,19 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
// char* p = alloca();
// read(p);
// c = *p;
- if (isa<SymbolicRegion>(MR) || isa<AllocaRegion>(MR))
- return UnknownVal();
+ if (isa<AllocaRegion>(MR))
+ return SValuator::CastResult(state, UnknownVal());
+
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(MR))
+ MR = GetElementZeroRegion(SR, T);
+
+ if (isa<CodeTextRegion>(MR))
+ return SValuator::CastResult(state, UnknownVal());
// FIXME: Perhaps this method should just take a 'const MemRegion*' argument
// instead of 'Loc', and have the other Loc cases handled at a higher level.
const TypedRegion *R = cast<TypedRegion>(MR);
- assert(R && "bad region");
+ QualType RTy = R->getValueType(getContext());
// FIXME: We should eventually handle funny addressing. e.g.:
//
@@ -828,197 +988,319 @@ SVal RegionStoreManager::Retrieve(const GRState *state, Loc L, QualType T) {
//
// Such funny addressing will occur due to layering of regions.
- QualType RTy = R->getValueType(getContext());
+#if 0
+ ASTContext &Ctx = getContext();
+ if (!T.isNull() && IsReinterpreted(RTy, T, Ctx)) {
+ SVal ZeroIdx = ValMgr.makeZeroArrayIndex();
+ R = MRMgr.getElementRegion(T, ZeroIdx, R, Ctx);
+ RTy = T;
+ assert(Ctx.getCanonicalType(RTy) ==
+ Ctx.getCanonicalType(R->getValueType(Ctx)));
+ }
+#endif
if (RTy->isStructureType())
- return RetrieveStruct(state, R);
+ return SValuator::CastResult(state, RetrieveStruct(state, R));
+
+ // FIXME: Handle unions.
+ if (RTy->isUnionType())
+ return SValuator::CastResult(state, UnknownVal());
if (RTy->isArrayType())
- return RetrieveArray(state, R);
+ return SValuator::CastResult(state, RetrieveArray(state, R));
// FIXME: handle Vector types.
if (RTy->isVectorType())
- return UnknownVal();
+ return SValuator::CastResult(state, UnknownVal());
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
- return RetrieveField(state, FR);
+ return CastRetrievedVal(RetrieveField(state, FR), state, FR, T);
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R))
- return RetrieveElement(state, ER);
-
- RegionBindingsTy B = GetRegionBindings(state->getStore());
- RegionBindingsTy::data_type* V = B.lookup(R);
+ return CastRetrievedVal(RetrieveElement(state, ER), state, ER, T);
- // Check if the region has a binding.
- if (V)
- return *V;
+ if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R))
+ return CastRetrievedVal(RetrieveObjCIvar(state, IVR), state, IVR, T);
- if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
- const MemRegion *SR = IVR->getSuperRegion();
+ if (const VarRegion *VR = dyn_cast<VarRegion>(R))
+ return CastRetrievedVal(RetrieveVar(state, VR), state, VR, T);
- // If the super region is 'self' then return the symbol representing
- // the value of the ivar upon entry to the method.
- if (SR == SelfRegion) {
- // FIXME: Do we need to handle the case where the super region
- // has a view? We want to canonicalize the bindings.
- return ValMgr.getRegionValueSymbolVal(R);
- }
-
- // Otherwise, we need a new symbol. For now return Unknown.
- return UnknownVal();
- }
+ RegionBindings B = GetRegionBindings(state->getStore());
+ RegionBindings::data_type* V = B.lookup(R);
+
+ // Check if the region has a binding.
+ if (V)
+ if (SVal const *SV = V->getValue())
+ return SValuator::CastResult(state, *SV);
// The location does not have a bound value. This means that it has
// the value it had upon its creation and/or entry to the analyzed
// function/method. These are either symbolic values or 'undefined'.
- // We treat function parameters as symbolic values.
- if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
- const VarDecl *VD = VR->getDecl();
-
- if (VD == SelfDecl)
- return loc::MemRegionVal(getSelfRegion(0));
-
- if (VR->hasGlobalsOrParametersStorage())
- return ValMgr.getRegionValueSymbolValOrUnknown(VR, VD->getType());
- }
-
+#if HEAP_UNDEFINED
if (R->hasHeapOrStackStorage()) {
+#else
+ if (R->hasStackStorage()) {
+#endif
// All stack variables are considered to have undefined values
// upon creation. All heap allocated blocks are considered to
// have undefined values as well unless they are explicitly bound
// to specific values.
- return UndefinedVal();
+ return SValuator::CastResult(state, UndefinedVal());
+ }
+
+ // All other values are symbolic.
+ return SValuator::CastResult(state,
+ ValMgr.getRegionValueSymbolValOrUnknown(R, RTy));
+}
+
+std::pair<const GRState*, const MemRegion*>
+RegionStoreManager::GetLazyBinding(RegionBindings B, const MemRegion *R) {
+ if (Optional<SVal> OV = getDirectBinding(B, R))
+ if (const nonloc::LazyCompoundVal *V =
+ dyn_cast<nonloc::LazyCompoundVal>(OV.getPointer()))
+ return std::make_pair(V->getState(), V->getRegion());
+
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ const std::pair<const GRState *, const MemRegion *> &X =
+ GetLazyBinding(B, ER->getSuperRegion());
+
+ if (X.first)
+ return std::make_pair(X.first,
+ MRMgr.getElementRegionWithSuper(ER, X.second));
}
+ else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
+ const std::pair<const GRState *, const MemRegion *> &X =
+ GetLazyBinding(B, FR->getSuperRegion());
- // If the region is already cast to another type, use that type to create the
- // symbol value.
- if (const QualType *p = state->get<RegionCasts>(R)) {
- QualType T = *p;
- RTy = T->getAsPointerType()->getPointeeType();
+ if (X.first)
+ return std::make_pair(X.first,
+ MRMgr.getFieldRegionWithSuper(FR, X.second));
}
- // All other values are symbolic.
- return ValMgr.getRegionValueSymbolValOrUnknown(R, RTy);
+ return std::make_pair((const GRState*) 0, (const MemRegion *) 0);
}
SVal RegionStoreManager::RetrieveElement(const GRState* state,
const ElementRegion* R) {
// Check if the region has a binding.
- RegionBindingsTy B = GetRegionBindings(state->getStore());
- if (const SVal* V = B.lookup(R))
+ RegionBindings B = GetRegionBindings(state->getStore());
+ if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
const MemRegion* superR = R->getSuperRegion();
// Check if the region is an element region of a string literal.
if (const StringRegion *StrR=dyn_cast<StringRegion>(superR)) {
+ // FIXME: Handle loads from strings where the literal is treated as
+ // an integer, e.g., *((unsigned int*)"hello")
+ ASTContext &Ctx = getContext();
+ QualType T = StrR->getValueType(Ctx)->getAs<ArrayType>()->getElementType();
+ if (T != Ctx.getCanonicalType(R->getElementType()))
+ return UnknownVal();
+
const StringLiteral *Str = StrR->getStringLiteral();
SVal Idx = R->getIndex();
if (nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Idx)) {
int64_t i = CI->getValue().getSExtValue();
- char c;
- if (i == Str->getByteLength())
- c = '\0';
- else
- c = Str->getStrData()[i];
- return ValMgr.makeIntVal(c, getContext().CharTy);
+ int64_t byteLength = Str->getByteLength();
+ if (i > byteLength) {
+ // Buffer overflow checking in GRExprEngine should handle this case,
+ // but we shouldn't rely on it to not overflow here if that checking
+ // is disabled.
+ return UnknownVal();
+ }
+ char c = (i == byteLength) ? '\0' : Str->getStrData()[i];
+ return ValMgr.makeIntVal(c, T);
}
}
- // Check if the super region has a default value.
- if (const SVal *D = state->get<RegionDefaultValue>(superR)) {
- if (D->hasConjuredSymbol())
- return ValMgr.getRegionValueSymbolVal(R);
- else
- return *D;
+ // Special case: the current region represents a cast and it and the super
+ // region both have pointer types or intptr_t types. If so, perform the
+ // retrieve from the super region and appropriately "cast" the value.
+ // This is needed to support OSAtomicCompareAndSwap and friends or other
+ // loads that treat integers as pointers and vis versa.
+ if (R->getIndex().isZeroConstant()) {
+ if (const TypedRegion *superTR = dyn_cast<TypedRegion>(superR)) {
+ ASTContext &Ctx = getContext();
+ if (IsAnyPointerOrIntptr(superTR->getValueType(Ctx), Ctx)) {
+ QualType valTy = R->getValueType(Ctx);
+ if (IsAnyPointerOrIntptr(valTy, Ctx)) {
+ // Retrieve the value from the super region. This will be casted to
+ // valTy when we return to 'Retrieve'.
+ const SValuator::CastResult &cr = Retrieve(state,
+ loc::MemRegionVal(superR),
+ valTy);
+ return cr.getSVal();
+ }
+ }
+ }
}
- // Check if the super region has a binding.
- if (B.lookup(superR)) {
- // We do not extract the bit value from super region for now.
+ // Check if the immediate super region has a direct binding.
+ if (Optional<SVal> V = getDirectBinding(B, superR)) {
+ if (SymbolRef parentSym = V->getAsSymbol())
+ return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
+
+ if (V->isUnknownOrUndef())
+ return *V;
+
+ // Handle LazyCompoundVals for the immediate super region. Other cases
+ // are handled in 'RetrieveFieldOrElementCommon'.
+ if (const nonloc::LazyCompoundVal *LCV =
+ dyn_cast<nonloc::LazyCompoundVal>(V)) {
+
+ R = MRMgr.getElementRegionWithSuper(R, LCV->getRegion());
+ return RetrieveElement(LCV->getState(), R);
+ }
+
+ // Other cases: give up.
return UnknownVal();
}
- if (R->hasHeapStorage()) {
- // FIXME: If the region has heap storage and we know nothing special
- // about its bindings, should we instead return UnknownVal? Seems like
- // we should only return UndefinedVal in the cases where we know the value
- // will be undefined.
- return UndefinedVal();
+ return RetrieveFieldOrElementCommon(state, R, R->getElementType(), superR);
+}
+
+SVal RegionStoreManager::RetrieveField(const GRState* state,
+ const FieldRegion* R) {
+
+ // Check if the region has a binding.
+ RegionBindings B = GetRegionBindings(state->getStore());
+ if (Optional<SVal> V = getDirectBinding(B, R))
+ return *V;
+
+ QualType Ty = R->getValueType(getContext());
+ return RetrieveFieldOrElementCommon(state, R, Ty, R->getSuperRegion());
+}
+
+SVal RegionStoreManager::RetrieveFieldOrElementCommon(const GRState *state,
+ const TypedRegion *R,
+ QualType Ty,
+ const MemRegion *superR) {
+
+ // At this point we have already checked in either RetrieveElement or
+ // RetrieveField if 'R' has a direct binding.
+
+ RegionBindings B = GetRegionBindings(state->getStore());
+
+ while (superR) {
+ if (const Optional<SVal> &D = getDefaultBinding(B, superR)) {
+ if (SymbolRef parentSym = D->getAsSymbol())
+ return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
+
+ if (D->isZeroConstant())
+ return ValMgr.makeZeroVal(Ty);
+
+ if (D->isUnknown())
+ return *D;
+
+ assert(0 && "Unknown default value");
+ }
+
+ // If our super region is a field or element itself, walk up the region
+ // hierarchy to see if there is a default value installed in an ancestor.
+ if (isa<FieldRegion>(superR) || isa<ElementRegion>(superR)) {
+ superR = cast<SubRegion>(superR)->getSuperRegion();
+ continue;
+ }
+
+ break;
+ }
+
+ // Lazy binding?
+ const GRState *lazyBindingState = NULL;
+ const MemRegion *lazyBindingRegion = NULL;
+ llvm::tie(lazyBindingState, lazyBindingRegion) = GetLazyBinding(B, R);
+
+ if (lazyBindingState) {
+ assert(lazyBindingRegion && "Lazy-binding region not set");
+
+ if (isa<ElementRegion>(R))
+ return RetrieveElement(lazyBindingState,
+ cast<ElementRegion>(lazyBindingRegion));
+
+ return RetrieveField(lazyBindingState,
+ cast<FieldRegion>(lazyBindingRegion));
}
if (R->hasStackStorage() && !R->hasParametersStorage()) {
- // Currently we don't reason specially about Clang-style vectors. Check
- // if superR is a vector and if so return Unknown.
- if (const TypedRegion *typedSuperR = dyn_cast<TypedRegion>(superR)) {
- if (typedSuperR->getValueType(getContext())->isVectorType())
- return UnknownVal();
+
+ if (isa<ElementRegion>(R)) {
+ // Currently we don't reason specially about Clang-style vectors. Check
+ // if superR is a vector and if so return Unknown.
+ if (const TypedRegion *typedSuperR = dyn_cast<TypedRegion>(superR)) {
+ if (typedSuperR->getValueType(getContext())->isVectorType())
+ return UnknownVal();
+ }
}
return UndefinedVal();
}
- QualType Ty = R->getValueType(getContext());
+ // All other values are symbolic.
+ return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty);
+}
- // If the region is already cast to another type, use that type to create the
- // symbol value.
- if (const QualType *p = state->get<RegionCasts>(R))
- Ty = (*p)->getAsPointerType()->getPointeeType();
+SVal RegionStoreManager::RetrieveObjCIvar(const GRState* state,
+ const ObjCIvarRegion* R) {
- return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty);
+ // Check if the region has a binding.
+ RegionBindings B = GetRegionBindings(state->getStore());
+
+ if (Optional<SVal> V = getDirectBinding(B, R))
+ return *V;
+
+ const MemRegion *superR = R->getSuperRegion();
+
+ // Check if the super region has a binding.
+ if (Optional<SVal> V = getDirectBinding(B, superR)) {
+ if (SymbolRef parentSym = V->getAsSymbol())
+ return ValMgr.getDerivedRegionValueSymbolVal(parentSym, R);
+
+ // Other cases: give up.
+ return UnknownVal();
+ }
+
+ return RetrieveLazySymbol(state, R);
}
-SVal RegionStoreManager::RetrieveField(const GRState* state,
- const FieldRegion* R) {
- QualType Ty = R->getValueType(getContext());
+SVal RegionStoreManager::RetrieveVar(const GRState *state,
+ const VarRegion *R) {
// Check if the region has a binding.
- RegionBindingsTy B = GetRegionBindings(state->getStore());
- if (const SVal* V = B.lookup(R))
+ RegionBindings B = GetRegionBindings(state->getStore());
+
+ if (Optional<SVal> V = getDirectBinding(B, R))
return *V;
- const MemRegion* superR = R->getSuperRegion();
- if (const SVal* D = state->get<RegionDefaultValue>(superR)) {
- if (D->hasConjuredSymbol())
- return ValMgr.getRegionValueSymbolVal(R);
+ // Lazily derive a value for the VarRegion.
+ const VarDecl *VD = R->getDecl();
- if (D->isZeroConstant())
- return ValMgr.makeZeroVal(Ty);
+ if (R->hasGlobalsOrParametersStorage())
+ return ValMgr.getRegionValueSymbolValOrUnknown(R, VD->getType());
- if (D->isUnknown())
- return *D;
+ return UndefinedVal();
+}
- assert(0 && "Unknown default value");
- }
+SVal RegionStoreManager::RetrieveLazySymbol(const GRState *state,
+ const TypedRegion *R) {
- // FIXME: Is this correct? Should it be UnknownVal?
- if (R->hasHeapStorage())
- return UndefinedVal();
-
- if (R->hasStackStorage() && !R->hasParametersStorage())
- return UndefinedVal();
-
- // If the region is already cast to another type, use that type to create the
- // symbol value.
- if (const QualType *p = state->get<RegionCasts>(R)) {
- QualType tmp = *p;
- Ty = tmp->getAsPointerType()->getPointeeType();
- }
+ QualType valTy = R->getValueType(getContext());
// All other values are symbolic.
- return ValMgr.getRegionValueSymbolValOrUnknown(R, Ty);
+ return ValMgr.getRegionValueSymbolValOrUnknown(R, valTy);
}
-SVal RegionStoreManager::RetrieveStruct(const GRState *state,
- const TypedRegion* R){
+SVal RegionStoreManager::RetrieveStruct(const GRState *state,
+ const TypedRegion* R) {
QualType T = R->getValueType(getContext());
assert(T->isStructureType());
const RecordType* RT = T->getAsStructureType();
RecordDecl* RD = RT->getDecl();
assert(RD->isDefinition());
-
+ (void)RD;
+#if USE_EXPLICIT_COMPOUND
llvm::ImmutableList<SVal> StructVal = getBasicVals().getEmptySValList();
// FIXME: We shouldn't use a std::vector. If RecordDecl doesn't have a
@@ -1030,33 +1312,38 @@ SVal RegionStoreManager::RetrieveStruct(const GRState *state,
Field != FieldEnd; ++Field) {
FieldRegion* FR = MRMgr.getFieldRegion(*Field, R);
QualType FTy = (*Field)->getType();
- SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy);
+ SVal FieldValue = Retrieve(state, loc::MemRegionVal(FR), FTy).getSVal();
StructVal = getBasicVals().consVals(FieldValue, StructVal);
}
return ValMgr.makeCompoundVal(T, StructVal);
+#else
+ return ValMgr.makeLazyCompoundVal(state, R);
+#endif
}
SVal RegionStoreManager::RetrieveArray(const GRState *state,
const TypedRegion * R) {
-
+#if USE_EXPLICIT_COMPOUND
QualType T = R->getValueType(getContext());
ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
llvm::ImmutableList<SVal> ArrayVal = getBasicVals().getEmptySValList();
- llvm::APSInt Size(CAT->getSize(), false);
- llvm::APSInt i = getBasicVals().getZeroWithPtrWidth(false);
-
- for (; i < Size; ++i) {
- SVal Idx = ValMgr.makeIntVal(i);
+ uint64_t size = CAT->getSize().getZExtValue();
+ for (uint64_t i = 0; i < size; ++i) {
+ SVal Idx = ValMgr.makeArrayIndex(i);
ElementRegion* ER = MRMgr.getElementRegion(CAT->getElementType(), Idx, R,
- getContext());
+ getContext());
QualType ETy = ER->getElementType();
- SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy);
+ SVal ElementVal = Retrieve(state, loc::MemRegionVal(ER), ETy).getSVal();
ArrayVal = getBasicVals().consVals(ElementVal, ArrayVal);
}
return ValMgr.makeCompoundVal(T, ArrayVal);
+#else
+ assert(isa<ConstantArrayType>(R->getValueType(getContext())));
+ return ValMgr.makeLazyCompoundVal(state, R);
+#endif
}
//===----------------------------------------------------------------------===//
@@ -1065,15 +1352,15 @@ SVal RegionStoreManager::RetrieveArray(const GRState *state,
Store RegionStoreManager::Remove(Store store, Loc L) {
const MemRegion* R = 0;
-
+
if (isa<loc::MemRegionVal>(L))
R = cast<loc::MemRegionVal>(L).getRegion();
-
+
if (R) {
- RegionBindingsTy B = GetRegionBindings(store);
+ RegionBindings B = GetRegionBindings(store);
return RBFactory.Remove(B, R).getRoot();
}
-
+
return store;
}
@@ -1082,32 +1369,67 @@ const GRState *RegionStoreManager::Bind(const GRState *state, Loc L, SVal V) {
return state;
// If we get here, the location should be a region.
- const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion();
-
+ const MemRegion *R = cast<loc::MemRegionVal>(L).getRegion();
+
// Check if the region is a struct region.
if (const TypedRegion* TR = dyn_cast<TypedRegion>(R))
if (TR->getValueType(getContext())->isStructureType())
return BindStruct(state, TR, V);
-
- RegionBindingsTy B = GetRegionBindings(state->getStore());
-
- B = RBFactory.Add(B, R, V);
-
- return state->makeWithStore(B.getRoot());
+
+ // Special case: the current region represents a cast and it and the super
+ // region both have pointer types or intptr_t types. If so, perform the
+ // bind to the super region.
+ // This is needed to support OSAtomicCompareAndSwap and friends or other
+ // loads that treat integers as pointers and vis versa.
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
+ if (ER->getIndex().isZeroConstant()) {
+ if (const TypedRegion *superR =
+ dyn_cast<TypedRegion>(ER->getSuperRegion())) {
+ ASTContext &Ctx = getContext();
+ QualType superTy = superR->getValueType(Ctx);
+ QualType erTy = ER->getValueType(Ctx);
+
+ if (IsAnyPointerOrIntptr(superTy, Ctx) &&
+ IsAnyPointerOrIntptr(erTy, Ctx)) {
+ SValuator::CastResult cr =
+ ValMgr.getSValuator().EvalCast(V, state, superTy, erTy);
+ return Bind(cr.getState(), loc::MemRegionVal(superR), cr.getSVal());
+ }
+ // For now, just invalidate the fields of the struct/union/class.
+ // FIXME: Precisely handle the fields of the record.
+ if (superTy->isRecordType())
+ return InvalidateRegion(state, superR, NULL, 0);
+ }
+ }
+ }
+ else if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
+ // Binding directly to a symbolic region should be treated as binding
+ // to element 0.
+ QualType T = SR->getSymbol()->getType(getContext());
+ T = T->getAs<PointerType>()->getPointeeType();
+ R = GetElementZeroRegion(SR, T);
+ }
+
+ // Perform the binding.
+ RegionBindings B = GetRegionBindings(state->getStore());
+ return state->makeWithStore(
+ RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
}
-const GRState *RegionStoreManager::BindDecl(const GRState *state,
- const VarDecl* VD, SVal InitVal) {
+const GRState *RegionStoreManager::BindDecl(const GRState *ST,
+ const VarDecl *VD,
+ const LocationContext *LC,
+ SVal InitVal) {
QualType T = VD->getType();
- VarRegion* VR = MRMgr.getVarRegion(VD);
+ VarRegion* VR = MRMgr.getVarRegion(VD, LC);
if (T->isArrayType())
- return BindArray(state, VR, InitVal);
+ return BindArray(ST, VR, InitVal);
if (T->isStructureType())
- return BindStruct(state, VR, InitVal);
+ return BindStruct(ST, VR, InitVal);
- return Bind(state, ValMgr.makeLoc(VR), InitVal);
+ return Bind(ST, ValMgr.makeLoc(VR), InitVal);
}
// FIXME: this method should be merged into Bind().
@@ -1115,21 +1437,20 @@ const GRState *
RegionStoreManager::BindCompoundLiteral(const GRState *state,
const CompoundLiteralExpr* CL,
SVal V) {
-
+
CompoundLiteralRegion* R = MRMgr.getCompoundLiteralRegion(CL);
return Bind(state, loc::MemRegionVal(R), V);
}
const GRState *RegionStoreManager::BindArray(const GRState *state,
- const TypedRegion* R,
+ const TypedRegion* R,
SVal Init) {
QualType T = R->getValueType(getContext());
ConstantArrayType* CAT = cast<ConstantArrayType>(T.getTypePtr());
QualType ElementTy = CAT->getElementType();
- llvm::APSInt Size(CAT->getSize(), false);
- llvm::APSInt i(llvm::APInt::getNullValue(Size.getBitWidth()), false);
+ uint64_t size = CAT->getSize().getZExtValue();
// Check if the init expr is a StringLiteral.
if (isa<loc::MemRegionVal>(Init)) {
@@ -1142,12 +1463,13 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
// Copy bytes from the string literal into the target array. Trailing bytes
// in the array that are not covered by the string literal are initialized
// to zero.
- for (; i < Size; ++i, ++j) {
+ for (uint64_t i = 0; i < size; ++i, ++j) {
if (j >= len)
break;
- SVal Idx = ValMgr.makeIntVal(i);
- ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx,R,getContext());
+ SVal Idx = ValMgr.makeArrayIndex(i);
+ ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R,
+ getContext());
SVal V = ValMgr.makeIntVal(str[j], sizeof(char)*8, true);
state = Bind(state, loc::MemRegionVal(ER), V);
@@ -1156,29 +1478,39 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
return state;
}
+ // Handle lazy compound values.
+ if (nonloc::LazyCompoundVal *LCV = dyn_cast<nonloc::LazyCompoundVal>(&Init))
+ return CopyLazyBindings(*LCV, state, R);
+
+ // Remaining case: explicit compound values.
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(Init);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
+ uint64_t i = 0;
- for (; i < Size; ++i, ++VI) {
+ for (; i < size; ++i, ++VI) {
// The init list might be shorter than the array length.
if (VI == VE)
break;
- SVal Idx = ValMgr.makeIntVal(i);
+ SVal Idx = ValMgr.makeArrayIndex(i);
ElementRegion* ER = MRMgr.getElementRegion(ElementTy, Idx, R, getContext());
if (CAT->getElementType()->isStructureType())
state = BindStruct(state, ER, *VI);
else
+ // FIXME: Do we need special handling of nested arrays?
state = Bind(state, ValMgr.makeLoc(ER), *VI);
}
// If the init list is shorter than the array length, set the array default
// value.
- if (i < Size) {
+ if (i < size) {
if (ElementTy->isIntegerType()) {
SVal V = ValMgr.makeZeroVal(ElementTy);
- state = setDefaultValue(state, R, V);
+ Store store = state->getStore();
+ RegionBindings B = GetRegionBindings(store);
+ B = RBFactory.Add(B, R, BindingVal(V, BindingVal::Default));
+ state = state->makeWithStore(B.getRoot());
}
}
@@ -1188,23 +1520,27 @@ const GRState *RegionStoreManager::BindArray(const GRState *state,
const GRState *
RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
SVal V) {
-
+
if (!Features.supportsFields())
return state;
-
+
QualType T = R->getValueType(getContext());
assert(T->isStructureType());
- const RecordType* RT = T->getAsRecordType();
+ const RecordType* RT = T->getAs<RecordType>();
RecordDecl* RD = RT->getDecl();
if (!RD->isDefinition())
return state;
+ // Handle lazy compound values.
+ if (const nonloc::LazyCompoundVal *LCV=dyn_cast<nonloc::LazyCompoundVal>(&V))
+ return CopyLazyBindings(*LCV, state, R);
+
// We may get non-CompoundVal accidentally due to imprecise cast logic.
// Ignore them and kill the field values.
if (V.isUnknown() || !isa<nonloc::CompoundVal>(V))
- return KillStruct(state, R);
+ return state->makeWithStore(KillStruct(state->getStore(), R));
nonloc::CompoundVal& CV = cast<nonloc::CompoundVal>(V);
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
@@ -1217,253 +1553,286 @@ RegionStoreManager::BindStruct(const GRState *state, const TypedRegion* R,
break;
QualType FTy = (*FI)->getType();
- FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
+ const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
- if (Loc::IsLocType(FTy) || FTy->isIntegerType())
- state = Bind(state, ValMgr.makeLoc(FR), *VI);
- else if (FTy->isArrayType())
+ if (FTy->isArrayType())
state = BindArray(state, FR, *VI);
else if (FTy->isStructureType())
state = BindStruct(state, FR, *VI);
+ else
+ state = Bind(state, ValMgr.makeLoc(FR), *VI);
}
// There may be fewer values in the initialize list than the fields of struct.
- if (FI != FE)
- state = setDefaultValue(state, R, ValMgr.makeIntVal(0, false));
+ if (FI != FE) {
+ Store store = state->getStore();
+ RegionBindings B = GetRegionBindings(store);
+ B = RBFactory.Add(B, R,
+ BindingVal(ValMgr.makeIntVal(0, false), BindingVal::Default));
+ state = state->makeWithStore(B.getRoot());
+ }
return state;
}
-const GRState *RegionStoreManager::KillStruct(const GRState *state,
- const TypedRegion* R){
+Store RegionStoreManager::KillStruct(Store store, const TypedRegion* R) {
+ RegionBindings B = GetRegionBindings(store);
+ llvm::OwningPtr<RegionStoreSubRegionMap>
+ SubRegions(getRegionStoreSubRegionMap(store));
+ RemoveSubRegionBindings(B, R, *SubRegions);
// Set the default value of the struct region to "unknown".
- state = state->set<RegionDefaultValue>(R, UnknownVal());
-
- // Remove all bindings for the subregions of the struct.
- Store store = state->getStore();
- RegionBindingsTy B = GetRegionBindings(store);
- for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- const MemRegion* R = I.getKey();
- if (const SubRegion* subRegion = dyn_cast<SubRegion>(R))
- if (subRegion->isSubRegionOf(R))
- store = Remove(store, ValMgr.makeLoc(subRegion));
- }
-
- return state->makeWithStore(store);
-}
+ B = RBFactory.Add(B, R, BindingVal(UnknownVal(), BindingVal::Default));
-//===----------------------------------------------------------------------===//
-// Region views.
-//===----------------------------------------------------------------------===//
-
-const GRState *RegionStoreManager::AddRegionView(const GRState *state,
- const MemRegion* View,
- const MemRegion* Base) {
-
- // First, retrieve the region view of the base region.
- const RegionViews* d = state->get<RegionViewMap>(Base);
- RegionViews L = d ? *d : RVFactory.GetEmptySet();
-
- // Now add View to the region view.
- L = RVFactory.Add(L, View);
-
- // Create a new state with the new region view.
- return state->set<RegionViewMap>(Base, L);
+ return B.getRoot();
}
-const GRState *RegionStoreManager::RemoveRegionView(const GRState *state,
- const MemRegion* View,
- const MemRegion* Base) {
- // Retrieve the region view of the base region.
- const RegionViews* d = state->get<RegionViewMap>(Base);
+const GRState*
+RegionStoreManager::CopyLazyBindings(nonloc::LazyCompoundVal V,
+ const GRState *state,
+ const TypedRegion *R) {
- // If the base region has no view, return.
- if (!d)
- return state;
+ // Nuke the old bindings stemming from R.
+ RegionBindings B = GetRegionBindings(state->getStore());
- // Remove the view.
- return state->set<RegionViewMap>(Base, RVFactory.Remove(*d, View));
-}
+ llvm::OwningPtr<RegionStoreSubRegionMap>
+ SubRegions(getRegionStoreSubRegionMap(state->getStore()));
-const GRState *RegionStoreManager::setCastType(const GRState *state,
- const MemRegion* R, QualType T) {
- return state->set<RegionCasts>(R, T);
-}
+ // B and DVM are updated after the call to RemoveSubRegionBindings.
+ RemoveSubRegionBindings(B, R, *SubRegions.get());
-const GRState *RegionStoreManager::setDefaultValue(const GRState *state,
- const MemRegion* R, SVal V) {
- return state->set<RegionDefaultValue>(R, V);
+ // Now copy the bindings. This amounts to just binding 'V' to 'R'. This
+ // results in a zero-copy algorithm.
+ return state->makeWithStore(
+ RBFactory.Add(B, R, BindingVal(V, BindingVal::Direct)).getRoot());
}
//===----------------------------------------------------------------------===//
// State pruning.
//===----------------------------------------------------------------------===//
-static void UpdateLiveSymbols(SVal X, SymbolReaper& SymReaper) {
- if (loc::MemRegionVal *XR = dyn_cast<loc::MemRegionVal>(&X)) {
- const MemRegion *R = XR->getRegion();
-
- while (R) {
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) {
- SymReaper.markLive(SR->getSymbol());
- return;
- }
-
- if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
- R = SR->getSuperRegion();
- continue;
- }
-
- break;
- }
-
- return;
- }
+namespace {
+class VISIBILITY_HIDDEN RBDNode
+ : public std::pair<const GRState*, const MemRegion *> {
+public:
+ RBDNode(const GRState *st, const MemRegion *r)
+ : std::pair<const GRState*, const MemRegion*>(st, r) {}
- for (SVal::symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end();SI!=SE;++SI)
- SymReaper.markLive(*SI);
-}
+ const GRState *getState() const { return first; }
+ const MemRegion *getRegion() const { return second; }
+};
-Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
- SymbolReaper& SymReaper,
- llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
-{
- Store store = state->getStore();
- RegionBindingsTy B = GetRegionBindings(store);
-
- // Lazily constructed backmap from MemRegions to SubRegions.
- typedef llvm::ImmutableSet<const MemRegion*> SubRegionsTy;
- typedef llvm::ImmutableMap<const MemRegion*, SubRegionsTy> SubRegionsMapTy;
-
- // FIXME: As a future optimization we can modifiy BumpPtrAllocator to have
- // the ability to reuse memory. This way we can keep TmpAlloc around as
- // an instance variable of RegionStoreManager (avoiding repeated malloc
- // overhead).
- llvm::BumpPtrAllocator TmpAlloc;
+enum VisitFlag { NotVisited = 0, VisitedFromSubRegion, VisitedFromSuperRegion };
+
+class RBDItem : public RBDNode {
+private:
+ const VisitFlag VF;
- // Factory objects.
- SubRegionsMapTy::Factory SubRegMapF(TmpAlloc);
- SubRegionsTy::Factory SubRegF(TmpAlloc);
+public:
+ RBDItem(const GRState *st, const MemRegion *r, VisitFlag vf)
+ : RBDNode(st, r), VF(vf) {}
+
+ VisitFlag getVisitFlag() const { return VF; }
+};
+} // end anonymous namespace
+void RegionStoreManager::RemoveDeadBindings(GRState &state, Stmt* Loc,
+ SymbolReaper& SymReaper,
+ llvm::SmallVectorImpl<const MemRegion*>& RegionRoots)
+{
+ Store store = state.getStore();
+ RegionBindings B = GetRegionBindings(store);
+
// The backmap from regions to subregions.
- SubRegionsMapTy SubRegMap = SubRegMapF.GetEmptyMap();
+ llvm::OwningPtr<RegionStoreSubRegionMap>
+ SubRegions(getRegionStoreSubRegionMap(store));
- // Do a pass over the regions in the store. For VarRegions we check if
- // the variable is still live and if so add it to the list of live roots.
- // For other regions we populate our region backmap.
+ // Do a pass over the regions in the store. For VarRegions we check if
+ // the variable is still live and if so add it to the list of live roots.
+ // For other regions we populate our region backmap.
llvm::SmallVector<const MemRegion*, 10> IntermediateRoots;
- for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- IntermediateRoots.push_back(I.getKey());
+ // Scan the direct bindings for "intermediate" roots.
+ for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ const MemRegion *R = I.getKey();
+ IntermediateRoots.push_back(R);
}
+ // Process the "intermediate" roots to find if they are referenced by
+ // real roots.
+ llvm::SmallVector<RBDItem, 10> WorkList;
+ llvm::DenseMap<const MemRegion*,unsigned> IntermediateVisited;
+
while (!IntermediateRoots.empty()) {
const MemRegion* R = IntermediateRoots.back();
IntermediateRoots.pop_back();
+ unsigned &visited = IntermediateVisited[R];
+ if (visited)
+ continue;
+ visited = 1;
+
if (const VarRegion* VR = dyn_cast<VarRegion>(R)) {
- if (SymReaper.isLive(Loc, VR->getDecl())) {
- RegionRoots.push_back(VR); // This is a live "root".
- }
- }
- else if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
- if (SymReaper.isLive(SR->getSymbol()))
- RegionRoots.push_back(SR);
+ if (SymReaper.isLive(Loc, VR->getDecl()))
+ WorkList.push_back(RBDItem(&state, VR, VisitedFromSuperRegion));
+ continue;
}
- else {
- // Get the super region for R.
- const MemRegion* superR = cast<SubRegion>(R)->getSuperRegion();
-
- // Get the current set of subregions for SuperR.
- const SubRegionsTy* SRptr = SubRegMap.lookup(superR);
- SubRegionsTy SRs = SRptr ? *SRptr : SubRegF.GetEmptySet();
-
- // Add R to the subregions of SuperR.
- SubRegMap = SubRegMapF.Add(SubRegMap, superR, SubRegF.Add(SRs, R));
-
- // Super region may be VarRegion or subregion of another VarRegion. Add it
- // to the work list.
- if (isa<SubRegion>(superR))
- IntermediateRoots.push_back(superR);
+
+ if (const SymbolicRegion* SR = dyn_cast<SymbolicRegion>(R)) {
+ if (SymReaper.isLive(SR->getSymbol()))
+ WorkList.push_back(RBDItem(&state, SR, VisitedFromSuperRegion));
+ continue;
}
+
+ // Add the super region for R to the worklist if it is a subregion.
+ if (const SubRegion* superR =
+ dyn_cast<SubRegion>(cast<SubRegion>(R)->getSuperRegion()))
+ IntermediateRoots.push_back(superR);
+ }
+
+ // Enqueue the RegionRoots onto WorkList.
+ for (llvm::SmallVectorImpl<const MemRegion*>::iterator I=RegionRoots.begin(),
+ E=RegionRoots.end(); I!=E; ++I) {
+ WorkList.push_back(RBDItem(&state, *I, VisitedFromSuperRegion));
}
+ RegionRoots.clear();
- // Process the worklist of RegionRoots. This performs a "mark-and-sweep"
- // of the store. We want to find all live symbols and dead regions.
- llvm::SmallPtrSet<const MemRegion*, 10> Marked;
+ // Process the worklist.
+ typedef llvm::DenseMap<std::pair<const GRState*, const MemRegion*>, VisitFlag>
+ VisitMap;
+
+ VisitMap Visited;
- while (!RegionRoots.empty()) {
- // Dequeue the next region on the worklist.
- const MemRegion* R = RegionRoots.back();
- RegionRoots.pop_back();
+ while (!WorkList.empty()) {
+ RBDItem N = WorkList.back();
+ WorkList.pop_back();
+
+ // Have we visited this node before?
+ VisitFlag &VF = Visited[N];
+ if (VF >= N.getVisitFlag())
+ continue;
- // Check if we have already processed this region.
- if (Marked.count(R)) continue;
+ const MemRegion *R = N.getRegion();
+ const GRState *state_N = N.getState();
- // Mark this region as processed. This is needed for termination in case
- // a region is referenced more than once.
- Marked.insert(R);
+ // Enqueue subregions?
+ if (N.getVisitFlag() == VisitedFromSuperRegion) {
+ RegionStoreSubRegionMap *M;
+
+ if (&state == state_N)
+ M = SubRegions.get();
+ else {
+ RegionStoreSubRegionMap *& SM = SC[state_N];
+ if (!SM)
+ SM = getRegionStoreSubRegionMap(state_N->getStore());
+ M = SM;
+ }
+
+ RegionStoreSubRegionMap::iterator I, E;
+ for (llvm::tie(I, E) = M->begin_end(R); I != E; ++I)
+ WorkList.push_back(RBDItem(state_N, *I, VisitedFromSuperRegion));
+ }
+
+ // At this point, if we have already visited this region before, we are
+ // done.
+ if (VF != NotVisited) {
+ VF = N.getVisitFlag();
+ continue;
+ }
+ VF = N.getVisitFlag();
+ // Enqueue the super region.
+ if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
+ const MemRegion *superR = SR->getSuperRegion();
+ if (!isa<MemSpaceRegion>(superR)) {
+ // If 'R' is a field or an element, we want to keep the bindings
+ // for the other fields and elements around. The reason is that
+ // pointer arithmetic can get us to the other fields or elements.
+ // FIXME: add an assertion that this is always true.
+ VisitFlag NewVisit =
+ isa<FieldRegion>(R) || isa<ElementRegion>(R) || isa<ObjCIvarRegion>(R)
+ ? VisitedFromSuperRegion : VisitedFromSubRegion;
+
+ WorkList.push_back(RBDItem(state_N, superR, NewVisit));
+ }
+ }
+
// Mark the symbol for any live SymbolicRegion as "live". This means we
// should continue to track that symbol.
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.markLive(SymR->getSymbol());
+
+ Store store_N = state_N->getStore();
+ RegionBindings B_N = GetRegionBindings(store_N);
// Get the data binding for R (if any).
- RegionBindingsTy::data_type* Xptr = B.lookup(R);
- if (Xptr) {
- SVal X = *Xptr;
- UpdateLiveSymbols(X, SymReaper); // Update the set of live symbols.
+ Optional<SVal> V = getBinding(B_N, R);
+
+ if (V) {
+ // Check for lazy bindings.
+ if (const nonloc::LazyCompoundVal *LCV =
+ dyn_cast<nonloc::LazyCompoundVal>(V.getPointer())) {
- // If X is a region, then add it to the RegionRoots.
- if (const MemRegion *RX = X.getAsRegion()) {
- RegionRoots.push_back(RX);
-
- // Mark the super region of the RX as live.
- // e.g.: int x; char *y = (char*) &x; if (*y) ...
- // 'y' => element region. 'x' is its super region.
- // We only add one level super region for now.
- // FIXME: maybe multiple level of super regions should be added.
- if (const SubRegion *SR = dyn_cast<SubRegion>(RX)) {
- RegionRoots.push_back(SR->getSuperRegion());
- }
+ const LazyCompoundValData *D = LCV->getCVData();
+ WorkList.push_back(RBDItem(D->getState(), D->getRegion(),
+ VisitedFromSuperRegion));
+ }
+ else {
+ // Update the set of live symbols.
+ for (SVal::symbol_iterator SI=V->symbol_begin(), SE=V->symbol_end();
+ SI!=SE;++SI)
+ SymReaper.markLive(*SI);
+
+ // If V is a region, then add it to the worklist.
+ if (const MemRegion *RX = V->getAsRegion())
+ WorkList.push_back(RBDItem(state_N, RX, VisitedFromSuperRegion));
}
}
-
- // Get the subregions of R. These are RegionRoots as well since they
- // represent values that are also bound to R.
- const SubRegionsTy* SRptr = SubRegMap.lookup(R);
- if (!SRptr) continue;
- SubRegionsTy SR = *SRptr;
-
- for (SubRegionsTy::iterator I=SR.begin(), E=SR.end(); I!=E; ++I)
- RegionRoots.push_back(*I);
-
}
// We have now scanned the store, marking reachable regions and symbols
// as live. We now remove all the regions that are dead from the store
- // as well as update DSymbols with the set symbols that are now dead.
- for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
+ // as well as update DSymbols with the set symbols that are now dead.
+ for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) {
const MemRegion* R = I.getKey();
// If this region live? Is so, none of its symbols are dead.
- if (Marked.count(R))
+ if (Visited.find(std::make_pair(&state, R)) != Visited.end())
continue;
-
+
// Remove this dead region from the store.
store = Remove(store, ValMgr.makeLoc(R));
-
+
// Mark all non-live symbols that this region references as dead.
if (const SymbolicRegion* SymR = dyn_cast<SymbolicRegion>(R))
SymReaper.maybeDead(SymR->getSymbol());
-
- SVal X = I.getData();
+
+ SVal X = *I.getData().getValue();
SVal::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end();
- for (; SI != SE; ++SI) SymReaper.maybeDead(*SI);
+ for (; SI != SE; ++SI)
+ SymReaper.maybeDead(*SI);
}
-
- return store;
+
+ // Write the store back.
+ state.setStore(store);
+}
+
+GRState const *RegionStoreManager::EnterStackFrame(GRState const *state,
+ StackFrameContext const *frame) {
+ FunctionDecl const *FD = cast<FunctionDecl>(frame->getDecl());
+ CallExpr const *CE = cast<CallExpr>(frame->getCallSite());
+
+ FunctionDecl::param_const_iterator PI = FD->param_begin();
+
+ CallExpr::const_arg_iterator AI = CE->arg_begin(), AE = CE->arg_end();
+
+ // Copy the arg expression value to the arg variables.
+ for (; AI != AE; ++AI, ++PI) {
+ SVal ArgVal = state->getSVal(*AI);
+ MemRegion *R = MRMgr.getVarRegion(*PI, frame);
+ state = Bind(state, ValMgr.makeLoc(R), ArgVal);
+ }
+
+ return state;
}
//===----------------------------------------------------------------------===//
@@ -1472,11 +1841,9 @@ Store RegionStoreManager::RemoveDeadBindings(const GRState *state, Stmt* Loc,
void RegionStoreManager::print(Store store, llvm::raw_ostream& OS,
const char* nl, const char *sep) {
- RegionBindingsTy B = GetRegionBindings(store);
- OS << "Store:" << nl;
-
- for (RegionBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) {
- OS << ' '; I.getKey()->print(OS); OS << " : ";
- I.getData().print(OS); OS << nl;
- }
+ RegionBindings B = GetRegionBindings(store);
+ OS << "Store (direct bindings):" << nl;
+
+ for (RegionBindings::iterator I = B.begin(), E = B.end(); I != E; ++I)
+ OS << ' ' << I.getKey() << " : " << I.getData() << nl;
}