aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/RegionStore.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/StaticAnalyzer/Core/RegionStore.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/RegionStore.cpp459
1 files changed, 312 insertions, 147 deletions
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp
index 82db23dd6b..88c4eee4bb 100644
--- a/lib/StaticAnalyzer/Core/RegionStore.cpp
+++ b/lib/StaticAnalyzer/Core/RegionStore.cpp
@@ -19,10 +19,12 @@
#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/AnalysisContext.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h"
#include "llvm/ADT/ImmutableList.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/Optional.h"
@@ -318,10 +320,12 @@ public:
//===----------------------------------------------------------------------===//
namespace {
+class invalidateRegionsWorker;
class RegionStoreManager : public StoreManager {
public:
const RegionStoreFeatures Features;
+
RegionBindings::Factory RBFactory;
mutable ClusterBindings::Factory CBFactory;
@@ -331,10 +335,34 @@ private:
SValListTy> LazyBindingsMapTy;
LazyBindingsMapTy LazyBindingsMap;
+ /// The largest number of fields a struct can have and still be
+ /// considered "small".
+ ///
+ /// This is currently used to decide whether or not it is worth "forcing" a
+ /// LazyCompoundVal on bind.
+ ///
+ /// This is controlled by 'region-store-small-struct-limit' option.
+ /// To disable all small-struct-dependent behavior, set the option to "0".
+ unsigned SmallStructLimit;
+
+ /// \brief A helper used to populate the work list with the given set of
+ /// regions.
+ void populateWorkList(invalidateRegionsWorker &W,
+ ArrayRef<SVal> Values,
+ bool IsArrayOfConstRegions,
+ InvalidatedRegions *TopLevelRegions);
+
public:
RegionStoreManager(ProgramStateManager& mgr, const RegionStoreFeatures &f)
: StoreManager(mgr), Features(f),
- RBFactory(mgr.getAllocator()), CBFactory(mgr.getAllocator()) {}
+ RBFactory(mgr.getAllocator()), CBFactory(mgr.getAllocator()),
+ SmallStructLimit(0) {
+ if (SubEngine *Eng = StateMgr.getOwningEngine()) {
+ AnalyzerOptions &Options = Eng->getAnalysisManager().options;
+ SmallStructLimit =
+ Options.getOptionAsInteger("region-store-small-struct-limit", 2);
+ }
+ }
/// setImplicitDefaultValue - Set the default binding for the provided
@@ -365,12 +393,17 @@ public:
RegionBindingsRef B,
InvalidatedRegions *Invalidated);
- StoreRef invalidateRegions(Store store, ArrayRef<const MemRegion *> Regions,
+ StoreRef invalidateRegions(Store store,
+ ArrayRef<SVal> Values,
+ ArrayRef<SVal> ConstValues,
const Expr *E, unsigned Count,
const LocationContext *LCtx,
- InvalidatedSymbols &IS,
const CallEvent *Call,
- InvalidatedRegions *Invalidated);
+ InvalidatedSymbols &IS,
+ InvalidatedSymbols &ConstIS,
+ InvalidatedRegions *Invalidated,
+ InvalidatedRegions *InvalidatedTopLevel,
+ InvalidatedRegions *InvalidatedTopLevelConst);
bool scanReachableSymbols(Store S, const MemRegion *R,
ScanReachableSymbols &Callbacks);
@@ -396,19 +429,20 @@ public: // Part of public interface to class.
.getRootWithoutRetain(), *this);
}
- /// \brief Create a new store that binds a value to a compound literal.
- ///
- /// \param ST The original store whose bindings are the basis for the new
- /// store.
+ /// Attempt to extract the fields of \p LCV and bind them to the struct region
+ /// \p R.
///
- /// \param CL The compound literal to bind (the binding key).
+ /// This path is used when it seems advantageous to "force" loading the values
+ /// within a LazyCompoundVal to bind memberwise to the struct region, rather
+ /// than using a Default binding at the base of the entire region. This is a
+ /// heuristic attempting to avoid building long chains of LazyCompoundVals.
///
- /// \param LC The LocationContext for the binding.
- ///
- /// \param V The value to bind to the compound literal.
- StoreRef bindCompoundLiteral(Store ST,
- const CompoundLiteralExpr *CL,
- const LocationContext *LC, SVal V);
+ /// \returns The updated store bindings, or \c None if binding non-lazily
+ /// would be too expensive.
+ Optional<RegionBindingsRef> tryBindSmallStruct(RegionBindingsConstRef B,
+ const TypedValueRegion *R,
+ const RecordDecl *RD,
+ nonloc::LazyCompoundVal LCV);
/// BindStruct - Bind a compound value to a structure.
RegionBindingsRef bindStruct(RegionBindingsConstRef B,
@@ -477,8 +511,7 @@ public: // Part of public interface to class.
SVal getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
const TypedValueRegion *R,
- QualType Ty,
- const MemRegion *superR);
+ QualType Ty);
SVal getLazyBinding(const SubRegion *LazyBindingRegion,
RegionBindingsRef LazyBinding);
@@ -591,11 +624,23 @@ ento::CreateFieldsOnlyRegionStoreManager(ProgramStateManager &StMgr) {
//===----------------------------------------------------------------------===//
namespace {
+/// Used to determine which global regions are automatically included in the
+/// initial worklist of a ClusterAnalysis.
+enum GlobalsFilterKind {
+ /// Don't include any global regions.
+ GFK_None,
+ /// Only include system globals.
+ GFK_SystemOnly,
+ /// Include all global regions.
+ GFK_All
+};
+
template <typename DERIVED>
class ClusterAnalysis {
protected:
typedef llvm::DenseMap<const MemRegion *, const ClusterBindings *> ClusterMap;
- typedef SmallVector<const MemRegion *, 10> WorkList;
+ typedef llvm::PointerIntPair<const MemRegion *, 1, bool> WorkListElement;
+ typedef SmallVector<WorkListElement, 10> WorkList;
llvm::SmallPtrSet<const ClusterBindings *, 16> Visited;
@@ -606,19 +651,36 @@ protected:
SValBuilder &svalBuilder;
RegionBindingsRef B;
-
- const bool includeGlobals;
+private:
+ GlobalsFilterKind GlobalsFilter;
+
+protected:
const ClusterBindings *getCluster(const MemRegion *R) {
return B.lookup(R);
}
+ /// Returns true if the memory space of the given region is one of the global
+ /// regions specially included at the start of analysis.
+ bool isInitiallyIncludedGlobalRegion(const MemRegion *R) {
+ switch (GlobalsFilter) {
+ case GFK_None:
+ return false;
+ case GFK_SystemOnly:
+ return isa<GlobalSystemSpaceRegion>(R->getMemorySpace());
+ case GFK_All:
+ return isa<NonStaticGlobalSpaceRegion>(R->getMemorySpace());
+ }
+
+ llvm_unreachable("unknown globals filter");
+ }
+
public:
ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr,
- RegionBindingsRef b, const bool includeGlobals)
+ RegionBindingsRef b, GlobalsFilterKind GFK)
: RM(rm), Ctx(StateMgr.getContext()),
svalBuilder(StateMgr.getSValBuilder()),
- B(b), includeGlobals(includeGlobals) {}
+ B(b), GlobalsFilter(GFK) {}
RegionBindingsRef getRegionBindings() const { return B; }
@@ -636,41 +698,41 @@ public:
assert(!Cluster.isEmpty() && "Empty clusters should be removed");
static_cast<DERIVED*>(this)->VisitAddedToCluster(Base, Cluster);
- if (includeGlobals)
- if (isa<NonStaticGlobalSpaceRegion>(Base->getMemorySpace()))
- AddToWorkList(Base, &Cluster);
+ // If this is an interesting global region, add it the work list up front.
+ if (isInitiallyIncludedGlobalRegion(Base))
+ AddToWorkList(WorkListElement(Base), &Cluster);
}
}
- bool AddToWorkList(const MemRegion *R, const ClusterBindings *C) {
+ bool AddToWorkList(WorkListElement E, const ClusterBindings *C) {
if (C && !Visited.insert(C))
return false;
- WL.push_back(R);
+ WL.push_back(E);
return true;
}
- bool AddToWorkList(const MemRegion *R) {
- const MemRegion *baseR = R->getBaseRegion();
- return AddToWorkList(baseR, getCluster(baseR));
+ bool AddToWorkList(const MemRegion *R, bool Flag = false) {
+ const MemRegion *BaseR = R->getBaseRegion();
+ return AddToWorkList(WorkListElement(BaseR, Flag), getCluster(BaseR));
}
void RunWorkList() {
while (!WL.empty()) {
- const MemRegion *baseR = WL.pop_back_val();
+ WorkListElement E = WL.pop_back_val();
+ const MemRegion *BaseR = E.getPointer();
- // First visit the cluster.
- if (const ClusterBindings *Cluster = getCluster(baseR))
- static_cast<DERIVED*>(this)->VisitCluster(baseR, *Cluster);
-
- // Next, visit the base region.
- static_cast<DERIVED*>(this)->VisitBaseRegion(baseR);
+ static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR),
+ E.getInt());
}
}
-public:
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C) {}
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C) {}
- void VisitBaseRegion(const MemRegion *baseR) {}
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C) {}
+
+ void VisitCluster(const MemRegion *BaseR, const ClusterBindings *C,
+ bool Flag) {
+ static_cast<DERIVED*>(this)->VisitCluster(BaseR, C);
+ }
};
}
@@ -831,14 +893,22 @@ RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B,
const SubRegion *Top) {
BindingKey TopKey = BindingKey::Make(Top, BindingKey::Default);
const MemRegion *ClusterHead = TopKey.getBaseRegion();
+
if (Top == ClusterHead) {
// We can remove an entire cluster's bindings all in one go.
return B.remove(Top);
}
const ClusterBindings *Cluster = B.lookup(ClusterHead);
- if (!Cluster)
+ if (!Cluster) {
+ // If we're invalidating a region with a symbolic offset, we need to make
+ // sure we don't treat the base region as uninitialized anymore.
+ if (TopKey.hasSymbolicOffset()) {
+ const SubRegion *Concrete = TopKey.getConcreteOffsetRegion();
+ return B.addBinding(Concrete, BindingKey::Default, UnknownVal());
+ }
return B;
+ }
SmallVector<BindingPair, 32> Bindings;
collectSubRegionBindings(Bindings, svalBuilder, *Cluster, Top, TopKey,
@@ -852,7 +922,8 @@ RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B,
// If we're invalidating a region with a symbolic offset, we need to make sure
// we don't treat the base region as uninitialized anymore.
- // FIXME: This isn't very precise; see the example in the loop.
+ // FIXME: This isn't very precise; see the example in
+ // collectSubRegionBindings.
if (TopKey.hasSymbolicOffset()) {
const SubRegion *Concrete = TopKey.getConcreteOffsetRegion();
Result = Result.add(BindingKey::Make(Concrete, BindingKey::Default),
@@ -871,6 +942,7 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker>
unsigned Count;
const LocationContext *LCtx;
InvalidatedSymbols &IS;
+ InvalidatedSymbols &ConstIS;
StoreManager::InvalidatedRegions *Regions;
public:
invalidateRegionsWorker(RegionStoreManager &rm,
@@ -879,15 +951,16 @@ public:
const Expr *ex, unsigned count,
const LocationContext *lctx,
InvalidatedSymbols &is,
+ InvalidatedSymbols &inConstIS,
StoreManager::InvalidatedRegions *r,
- bool includeGlobals)
- : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, includeGlobals),
- Ex(ex), Count(count), LCtx(lctx), IS(is), Regions(r) {}
-
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitBaseRegion(const MemRegion *baseR);
-
-private:
+ GlobalsFilterKind GFK)
+ : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b, GFK),
+ Ex(ex), Count(count), LCtx(lctx), IS(is), ConstIS(inConstIS), Regions(r){}
+
+ /// \param IsConst Specifies if the region we are invalidating is constant.
+ /// If it is, we invalidate all subregions, but not the base region itself.
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C,
+ bool IsConst);
void VisitBinding(SVal V);
};
}
@@ -917,18 +990,17 @@ void invalidateRegionsWorker::VisitBinding(SVal V) {
}
}
-void invalidateRegionsWorker::VisitCluster(const MemRegion *BaseR,
- const ClusterBindings &C) {
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I)
- VisitBinding(I.getData());
-
- B = B.remove(BaseR);
-}
+void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
+ const ClusterBindings *C,
+ bool IsConst) {
+ if (C) {
+ for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
+ VisitBinding(I.getData());
-void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
- // Symbolic region? Mark that symbol touched by the invalidation.
- if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
- IS.insert(SR->getSymbol());
+ // Invalidate the contents of a non-const base region.
+ if (!IsConst)
+ B = B.remove(baseR);
+ }
// BlockDataRegion? If so, invalidate captured variables that are passed
// by reference.
@@ -957,6 +1029,21 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
return;
}
+ // Symbolic region?
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) {
+ SymbolRef RegionSym = SR->getSymbol();
+
+ // Mark that symbol touched by the invalidation.
+ if (IsConst)
+ ConstIS.insert(RegionSym);
+ else
+ IS.insert(RegionSym);
+ }
+
+ // Nothing else should be done for a const region.
+ if (IsConst)
+ return;
+
// Otherwise, we have a normal data region. Record that we touched the region.
if (Regions)
Regions->push_back(baseR);
@@ -976,7 +1063,13 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
const TypedValueRegion *TR = cast<TypedValueRegion>(baseR);
QualType T = TR->getValueType();
- // Invalidate the binding.
+ if (isInitiallyIncludedGlobalRegion(baseR)) {
+ // If the region is a global and we are invalidating all globals,
+ // erasing the entry is good enough. This causes all globals to be lazily
+ // symbolicated from the same base symbol.
+ return;
+ }
+
if (T->isStructureOrClassType()) {
// Invalidate the region by setting its default value to
// conjured symbol. The type of the symbol is irrelavant.
@@ -994,16 +1087,6 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) {
B = B.addBinding(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 = B.removeBinding(baseR);
- return;
- }
-
DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
T,Count);
@@ -1036,45 +1119,92 @@ RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
return B;
}
+void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W,
+ ArrayRef<SVal> Values,
+ bool IsArrayOfConstRegions,
+ InvalidatedRegions *TopLevelRegions) {
+ for (ArrayRef<SVal>::iterator I = Values.begin(),
+ E = Values.end(); I != E; ++I) {
+ SVal V = *I;
+ if (Optional<nonloc::LazyCompoundVal> LCS =
+ V.getAs<nonloc::LazyCompoundVal>()) {
+
+ const SValListTy &Vals = getInterestingValues(*LCS);
+
+ for (SValListTy::const_iterator I = Vals.begin(),
+ E = Vals.end(); I != E; ++I) {
+ // Note: the last argument is false here because these are
+ // non-top-level regions.
+ if (const MemRegion *R = (*I).getAsRegion())
+ W.AddToWorkList(R, /*IsConst=*/ false);
+ }
+ continue;
+ }
+
+ if (const MemRegion *R = V.getAsRegion()) {
+ if (TopLevelRegions)
+ TopLevelRegions->push_back(R);
+ W.AddToWorkList(R, /*IsConst=*/ IsArrayOfConstRegions);
+ continue;
+ }
+ }
+}
+
StoreRef
RegionStoreManager::invalidateRegions(Store store,
- ArrayRef<const MemRegion *> Regions,
+ ArrayRef<SVal> Values,
+ ArrayRef<SVal> ConstValues,
const Expr *Ex, unsigned Count,
const LocationContext *LCtx,
- InvalidatedSymbols &IS,
const CallEvent *Call,
+ InvalidatedSymbols &IS,
+ InvalidatedSymbols &ConstIS,
+ InvalidatedRegions *TopLevelRegions,
+ InvalidatedRegions *TopLevelConstRegions,
InvalidatedRegions *Invalidated) {
- invalidateRegionsWorker W(*this, StateMgr,
- RegionStoreManager::getRegionBindings(store),
- Ex, Count, LCtx, IS, Invalidated, false);
+ GlobalsFilterKind GlobalsFilter;
+ if (Call) {
+ if (Call->isInSystemHeader())
+ GlobalsFilter = GFK_SystemOnly;
+ else
+ GlobalsFilter = GFK_All;
+ } else {
+ GlobalsFilter = GFK_None;
+ }
+
+ RegionBindingsRef B = getRegionBindings(store);
+ invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ConstIS,
+ Invalidated, GlobalsFilter);
// Scan the bindings and generate the clusters.
W.GenerateClusters();
// Add the regions to the worklist.
- for (ArrayRef<const MemRegion *>::iterator
- I = Regions.begin(), E = Regions.end(); I != E; ++I)
- W.AddToWorkList(*I);
+ populateWorkList(W, Values, /*IsArrayOfConstRegions*/ false,
+ TopLevelRegions);
+ populateWorkList(W, ConstValues, /*IsArrayOfConstRegions*/ true,
+ TopLevelConstRegions);
W.RunWorkList();
// Return the new bindings.
- RegionBindingsRef B = W.getRegionBindings();
+ B = W.getRegionBindings();
- // For all globals which are not static nor immutable: determine which global
- // regions should be invalidated and invalidate them.
+ // For calls, determine which global regions should be invalidated and
+ // invalidate them. (Note that function-static and immutable globals are never
+ // invalidated by this.)
// TODO: This could possibly be more precise with modules.
- //
- // System calls invalidate only system globals.
- if (Call && Call->isInSystemHeader()) {
- B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
+ switch (GlobalsFilter) {
+ case GFK_All:
+ B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
Ex, Count, LCtx, B, Invalidated);
- // Internal calls might invalidate both system and internal globals.
- } else {
+ // FALLTHROUGH
+ case GFK_SystemOnly:
B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
Ex, Count, LCtx, B, Invalidated);
- B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
- Ex, Count, LCtx, B, Invalidated);
+ // FALLTHROUGH
+ case GFK_None:
+ break;
}
return StoreRef(B.asStore(), *this);
@@ -1265,6 +1395,17 @@ SVal RegionStoreManager::getBinding(RegionBindingsConstRef B, Loc L, QualType T)
return svalBuilder.getRegionValueSymbolVal(R);
}
+static QualType getUnderlyingType(const SubRegion *R) {
+ QualType RegionTy;
+ if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R))
+ RegionTy = TVR->getValueType();
+
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
+ RegionTy = SR->getSymbol()->getType();
+
+ return RegionTy;
+}
+
/// Checks to see if store \p B has a lazy binding for region \p R.
///
/// If \p AllowSubregionBindings is \c false, a lazy binding will be rejected
@@ -1283,11 +1424,11 @@ getExistingLazyBinding(SValBuilder &SVB, RegionBindingsConstRef B,
if (!LCV)
return None;
- // If the LCV is for a subregion, the types won't match, and we shouldn't
- // reuse the binding. Unfortuately we can only check this if the destination
- // region is a TypedValueRegion.
- if (const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(R)) {
- QualType RegionTy = TVR->getValueType();
+ // If the LCV is for a subregion, the types might not match, and we shouldn't
+ // reuse the binding.
+ QualType RegionTy = getUnderlyingType(R);
+ if (!RegionTy.isNull() &&
+ !RegionTy->isVoidPointerType()) {
QualType SourceRegionTy = LCV->getRegion()->getValueType();
if (!SVB.getContext().hasSameUnqualifiedType(RegionTy, SourceRegionTy))
return None;
@@ -1424,8 +1565,7 @@ SVal RegionStoreManager::getBindingForElement(RegionBindingsConstRef B,
}
}
}
- return getBindingForFieldOrElementCommon(B, R, R->getElementType(),
- superR);
+ return getBindingForFieldOrElementCommon(B, R, R->getElementType());
}
SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
@@ -1436,7 +1576,7 @@ SVal RegionStoreManager::getBindingForField(RegionBindingsConstRef B,
return *V;
QualType Ty = R->getValueType();
- return getBindingForFieldOrElementCommon(B, R, Ty, R->getSuperRegion());
+ return getBindingForFieldOrElementCommon(B, R, Ty);
}
Optional<SVal>
@@ -1499,8 +1639,7 @@ SVal RegionStoreManager::getLazyBinding(const SubRegion *LazyBindingRegion,
SVal
RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
const TypedValueRegion *R,
- QualType Ty,
- const MemRegion *superR) {
+ QualType Ty) {
// At this point we have already checked in either getBindingForElement or
// getBindingForField if 'R' has a direct binding.
@@ -1533,8 +1672,9 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
// quickly result in a warning.
bool hasPartialLazyBinding = false;
- const SubRegion *Base = dyn_cast<SubRegion>(superR);
- while (Base) {
+ const SubRegion *SR = dyn_cast<SubRegion>(R);
+ while (SR) {
+ const MemRegion *Base = SR->getSuperRegion();
if (Optional<SVal> D = getBindingForDerivedDefaultValue(B, Base, R, Ty)) {
if (D->getAs<nonloc::LazyCompoundVal>()) {
hasPartialLazyBinding = true;
@@ -1552,7 +1692,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
// 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.
- Base = dyn_cast<SubRegion>(Base->getSuperRegion());
+ SR = dyn_cast<SubRegion>(Base);
}
if (R->hasStackNonParametersStorage()) {
@@ -1560,7 +1700,7 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B,
// Currently we don't reason specially about Clang-style vectors. Check
// if superR is a vector and if so return Unknown.
if (const TypedValueRegion *typedSuperR =
- dyn_cast<TypedValueRegion>(superR)) {
+ dyn_cast<TypedValueRegion>(R->getSuperRegion())) {
if (typedSuperR->getValueType()->isVectorType())
return UnknownVal();
}
@@ -1601,26 +1741,6 @@ SVal RegionStoreManager::getBindingForObjCIvar(RegionBindingsConstRef B,
return getBindingForLazySymbol(R);
}
-static Optional<SVal> getConstValue(SValBuilder &SVB, const VarDecl *VD) {
- ASTContext &Ctx = SVB.getContext();
- if (!VD->getType().isConstQualified())
- return None;
-
- const Expr *Init = VD->getInit();
- if (!Init)
- return None;
-
- llvm::APSInt Result;
- if (!Init->isGLValue() && Init->EvaluateAsInt(Result, Ctx))
- return SVB.makeIntVal(Result);
-
- if (Init->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull))
- return SVB.makeNull();
-
- // FIXME: Handle other possible constant expressions.
- return None;
-}
-
SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
const VarRegion *R) {
@@ -1637,8 +1757,10 @@ SVal RegionStoreManager::getBindingForVar(RegionBindingsConstRef B,
return svalBuilder.getRegionValueSymbolVal(R);
// Is 'VD' declared constant? If so, retrieve the constant value.
- if (Optional<SVal> V = getConstValue(svalBuilder, VD))
- return *V;
+ if (VD->getType().isConstQualified())
+ if (const Expr *Init = VD->getInit())
+ if (Optional<SVal> V = svalBuilder.getConstantVal(Init))
+ return *V;
// This must come after the check for constants because closure-captured
// constant variables may appear in UnknownSpaceRegion.
@@ -1810,14 +1932,6 @@ RegionStoreManager::bind(RegionBindingsConstRef B, Loc L, SVal V) {
return NewB.addBinding(BindingKey::Make(R, BindingKey::Direct), V);
}
-// FIXME: this method should be merged into Bind().
-StoreRef RegionStoreManager::bindCompoundLiteral(Store ST,
- const CompoundLiteralExpr *CL,
- const LocationContext *LC,
- SVal V) {
- return Bind(ST, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), V);
-}
-
RegionBindingsRef
RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B,
const MemRegion *R,
@@ -1826,7 +1940,7 @@ RegionStoreManager::setImplicitDefaultValue(RegionBindingsConstRef B,
if (Loc::isLocType(T))
V = svalBuilder.makeNull();
- else if (T->isIntegerType())
+ else if (T->isIntegralOrEnumerationType())
V = svalBuilder.makeZeroVal(T);
else if (T->isStructureOrClassType() || T->isArrayType()) {
// Set the default value to a zero constant when it is a structure
@@ -1896,7 +2010,7 @@ RegionStoreManager::bindArray(RegionBindingsConstRef B,
else if (ElementTy->isArrayType())
NewB = bindArray(NewB, ER, *VI);
else
- NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI);
+ NewB = bind(NewB, loc::MemRegionVal(ER), *VI);
}
// If the init list is shorter than the array length, set the
@@ -1937,14 +2051,56 @@ RegionBindingsRef RegionStoreManager::bindVector(RegionBindingsConstRef B,
NonLoc Idx = svalBuilder.makeArrayIndex(index);
const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx);
-
+
if (ElemType->isArrayType())
NewB = bindArray(NewB, ER, *VI);
else if (ElemType->isStructureOrClassType())
NewB = bindStruct(NewB, ER, *VI);
else
- NewB = bind(NewB, svalBuilder.makeLoc(ER), *VI);
+ NewB = bind(NewB, loc::MemRegionVal(ER), *VI);
+ }
+ return NewB;
+}
+
+Optional<RegionBindingsRef>
+RegionStoreManager::tryBindSmallStruct(RegionBindingsConstRef B,
+ const TypedValueRegion *R,
+ const RecordDecl *RD,
+ nonloc::LazyCompoundVal LCV) {
+ FieldVector Fields;
+
+ if (const CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(RD))
+ if (Class->getNumBases() != 0 || Class->getNumVBases() != 0)
+ return None;
+
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I) {
+ const FieldDecl *FD = *I;
+ if (FD->isUnnamedBitfield())
+ continue;
+
+ // If there are too many fields, or if any of the fields are aggregates,
+ // just use the LCV as a default binding.
+ if (Fields.size() == SmallStructLimit)
+ return None;
+
+ QualType Ty = FD->getType();
+ if (!(Ty->isScalarType() || Ty->isReferenceType()))
+ return None;
+
+ Fields.push_back(*I);
}
+
+ RegionBindingsRef NewB = B;
+
+ for (FieldVector::iterator I = Fields.begin(), E = Fields.end(); I != E; ++I){
+ const FieldRegion *SourceFR = MRMgr.getFieldRegion(*I, LCV.getRegion());
+ SVal V = getBindingForField(getRegionBindings(LCV.getStore()), SourceFR);
+
+ const FieldRegion *DestFR = MRMgr.getFieldRegion(*I, R);
+ NewB = bind(NewB, loc::MemRegionVal(DestFR), V);
+ }
+
return NewB;
}
@@ -1958,13 +2114,19 @@ RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B,
assert(T->isStructureOrClassType());
const RecordType* RT = T->getAs<RecordType>();
- RecordDecl *RD = RT->getDecl();
+ const RecordDecl *RD = RT->getDecl();
if (!RD->isCompleteDefinition())
return B;
// Handle lazy compound values and symbolic values.
- if (V.getAs<nonloc::LazyCompoundVal>() || V.getAs<nonloc::SymbolVal>())
+ if (Optional<nonloc::LazyCompoundVal> LCV =
+ V.getAs<nonloc::LazyCompoundVal>()) {
+ if (Optional<RegionBindingsRef> NewB = tryBindSmallStruct(B, R, RD, *LCV))
+ return *NewB;
+ return bindAggregate(B, R, V);
+ }
+ if (V.getAs<nonloc::SymbolVal>())
return bindAggregate(B, R, V);
// We may get non-CompoundVal accidentally due to imprecise cast logic or
@@ -1996,7 +2158,7 @@ RegionBindingsRef RegionStoreManager::bindStruct(RegionBindingsConstRef B,
else if (FTy->isStructureOrClassType())
NewB = bindStruct(NewB, FR, *VI);
else
- NewB = bind(NewB, svalBuilder.makeLoc(FR), *VI);
+ NewB = bind(NewB, loc::MemRegionVal(FR), *VI);
++VI;
}
@@ -2034,13 +2196,13 @@ public:
ProgramStateManager &stateMgr,
RegionBindingsRef b, SymbolReaper &symReaper,
const StackFrameContext *LCtx)
- : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b,
- /* includeGlobals = */ false),
+ : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b, GFK_None),
SymReaper(symReaper), CurrentLCtx(LCtx) {}
// Called by ClusterAnalysis.
void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C);
- void VisitCluster(const MemRegion *baseR, const ClusterBindings &C);
+ void VisitCluster(const MemRegion *baseR, const ClusterBindings *C);
+ using ClusterAnalysis<removeDeadBindingsWorker>::VisitCluster;
bool UpdatePostponed();
void VisitBinding(SVal V);
@@ -2083,13 +2245,16 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
}
void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
- const ClusterBindings &C) {
+ const ClusterBindings *C) {
+ if (!C)
+ return;
+
// Mark the symbol for any SymbolicRegion with live bindings as live itself.
// This means we should continue to track that symbol.
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR))
SymReaper.markLive(SymR->getSymbol());
- for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I)
+ for (ClusterBindings::iterator I = C->begin(), E = C->end(); I != E; ++I)
VisitBinding(I.getData());
}