#include "llvm/ADT/ImmutableMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
#include <utility>
using namespace ento;
namespace {
class BindingKey {
public:
enum Kind { Default = 0x0, Direct = 0x1 };
private:
enum { Symbolic = 0x2 };
llvm::PointerIntPair<const MemRegion *, 2>
P;
explicit BindingKey(
const SubRegion *r,
const SubRegion *
Base, Kind k)
assert(r &&
Base &&
"Must have known regions.");
assert(getConcreteOffsetRegion() ==
Base &&
"Failed to store base region");
}
explicit BindingKey(const MemRegion *r, uint64_t offset, Kind k)
:
P(r, k),
Data(offset) {
assert(r && "Must have known regions.");
assert(getOffset() == offset && "Failed to store offset");
assert((r == r->getBaseRegion() ||
isa<ObjCIvarRegion, CXXDerivedObjectRegion>(r)) &&
"Not a base");
}
public:
bool isDirect()
const {
return P.getInt() & Direct; }
bool hasSymbolicOffset()
const {
return P.getInt() & Symbolic; }
const MemRegion *
getRegion()
const {
return P.getPointer(); }
uint64_t getOffset() const {
assert(!hasSymbolicOffset());
}
const SubRegion *getConcreteOffsetRegion() const {
assert(hasSymbolicOffset());
return reinterpret_cast<const SubRegion *
>(
static_cast<uintptr_t>(
Data));
}
const MemRegion *getBaseRegion() const {
if (hasSymbolicOffset())
return getConcreteOffsetRegion()->getBaseRegion();
}
void Profile(llvm::FoldingSetNodeID&
ID)
const {
ID.AddPointer(
P.getOpaqueValue());
}
static BindingKey Make(const MemRegion *R, Kind k);
bool operator<(
const BindingKey &
X)
const {
if (
P.getOpaqueValue() <
X.P.getOpaqueValue())
return true;
if (
P.getOpaqueValue() >
X.P.getOpaqueValue())
return false;
}
bool operator==(
const BindingKey &
X)
const {
return P.getOpaqueValue() ==
X.P.getOpaqueValue() &&
}
LLVM_DUMP_METHOD
void dump()
const;
};
}
BindingKey BindingKey::Make(
const MemRegion *R,
Kind k) {
const RegionOffset &RO = R->getAsOffset();
if (RO.hasSymbolicOffset())
return BindingKey(cast<SubRegion>(R), cast<SubRegion>(RO.getRegion()), k);
return BindingKey(RO.getRegion(), RO.getOffset(), k);
}
static inline raw_ostream &
operator<<(raw_ostream &Out, BindingKey K) {
Out << "\"kind\": \"" << (K.isDirect() ? "Direct" : "Default")
<< "\", \"offset\": ";
if (!K.hasSymbolicOffset())
Out << K.getOffset();
else
Out << "null";
return Out;
}
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
void BindingKey::dump() const { llvm::errs() << *this; }
#endif
typedef llvm::ImmutableMap<const MemRegion *, ClusterBindings>
namespace {
class RegionBindingsRef : public llvm::ImmutableMapRef<const MemRegion *,
ClusterBindings> {
ClusterBindings::Factory *CBFactory;
bool IsMainAnalysis;
public:
typedef llvm::ImmutableMapRef<const MemRegion *, ClusterBindings>
ParentTy;
RegionBindingsRef(ClusterBindings::Factory &CBFactory,
const RegionBindings::TreeTy *T,
RegionBindings::TreeTy::Factory *F,
bool IsMainAnalysis)
CBFactory(&CBFactory), IsMainAnalysis(IsMainAnalysis) {}
RegionBindingsRef(
const ParentTy &
P,
ClusterBindings::Factory &CBFactory,
bool IsMainAnalysis)
CBFactory(&CBFactory), IsMainAnalysis(IsMainAnalysis) {}
RegionBindingsRef add(key_type_ref K, data_type_ref
D)
const {
return RegionBindingsRef(
static_cast<const ParentTy *
>(
this)->add(K,
D),
*CBFactory, IsMainAnalysis);
}
RegionBindingsRef
remove(key_type_ref K)
const {
return RegionBindingsRef(
static_cast<const ParentTy *
>(
this)->
remove(K),
*CBFactory, IsMainAnalysis);
}
RegionBindingsRef addBinding(BindingKey K, SVal
V)
const;
RegionBindingsRef addBinding(const MemRegion *R,
BindingKey::Kind k, SVal
V)
const;
const SVal *lookup(BindingKey K) const;
const SVal *lookup(const MemRegion *R, BindingKey::Kind k) const;
RegionBindingsRef removeBinding(BindingKey K);
RegionBindingsRef removeBinding(const MemRegion *R,
BindingKey::Kind k);
RegionBindingsRef removeBinding(const MemRegion *R) {
return removeBinding(R, BindingKey::Direct).
removeBinding(R, BindingKey::Default);
}
std::optional<SVal> getDirectBinding(const MemRegion *R) const;
std::optional<SVal> getDefaultBinding(const MemRegion *R) const;
llvm::PointerIntPair<Store, 1, bool> Ptr = {
asImmutableMap().getRootWithoutRetain(), IsMainAnalysis};
return reinterpret_cast<Store>(Ptr.getOpaqueValue());
}
bool isMainAnalysis() const {
return IsMainAnalysis;
}
void printJson(raw_ostream &Out, const char *NL = "\n",
unsigned int Space = 0, bool IsDot = false) const {
for (iterator I = begin(),
E = end(); I !=
E; ++I) {
Indent(Out, Space, IsDot)
<< "{ \"cluster\": \"" << I.getKey() << "\", \"pointer\": \""
<< (const void *)I.getKey() << "\", \"items\": [" << NL;
++Space;
for (ClusterBindings::iterator CI = CB.begin(), CE = CB.end(); CI != CE;
++CI) {
Indent(Out, Space, IsDot) << "{ " << CI.getKey() << ", \"value\": ";
CI.getData().printJson(Out, true);
Out << " }";
if (std::next(CI) != CE)
Out << ',';
Out << NL;
}
--Space;
Indent(Out, Space, IsDot) << "]}";
Out << ',';
Out << NL;
}
}
LLVM_DUMP_METHOD
void dump()
const { printJson(llvm::errs()); }
};
}
std::optional<SVal>
RegionBindingsRef::getDirectBinding(const MemRegion *R) const {
const SVal *
V = lookup(R, BindingKey::Direct);
return V ? std::optional<SVal>(*
V) :
std::nullopt;
}
std::optional<SVal>
RegionBindingsRef::getDefaultBinding(const MemRegion *R) const {
const SVal *
V = lookup(R, BindingKey::Default);
return V ? std::optional<SVal>(*
V) :
std::nullopt;
}
RegionBindingsRef RegionBindingsRef::addBinding(BindingKey K, SVal
V)
const {
const MemRegion *
Base = K.getBaseRegion();
(ExistingCluster ? *ExistingCluster : CBFactory->getEmptyMap());
return add(
Base, NewCluster);
}
RegionBindingsRef RegionBindingsRef::addBinding(const MemRegion *R,
BindingKey::Kind k,
return addBinding(BindingKey::Make(R, k),
V);
}
const SVal *RegionBindingsRef::lookup(BindingKey K) const {
if (!Cluster)
return nullptr;
return Cluster->lookup(K);
}
const SVal *RegionBindingsRef::lookup(const MemRegion *R,
BindingKey::Kind k) const {
return lookup(BindingKey::Make(R, k));
}
RegionBindingsRef RegionBindingsRef::removeBinding(BindingKey K) {
const MemRegion *
Base = K.getBaseRegion();
if (!Cluster)
return *this;
if (NewCluster.isEmpty())
return add(
Base, NewCluster);
}
RegionBindingsRef RegionBindingsRef::removeBinding(const MemRegion *R,
BindingKey::Kind k){
return removeBinding(BindingKey::Make(R, k));
}
namespace {
class InvalidateRegionsWorker;
class RegionStoreManager : public StoreManager {
public:
RegionBindings::Factory RBFactory;
mutable ClusterBindings::Factory CBFactory;
typedef std::vector<SVal> SValListTy;
private:
typedef llvm::DenseMap<const LazyCompoundValData *,
SValListTy> LazyBindingsMapTy;
LazyBindingsMapTy LazyBindingsMap;
unsigned SmallStructLimit;
unsigned SmallArrayLimit;
void populateWorkList(InvalidateRegionsWorker &W,
InvalidatedRegions *TopLevelRegions);
public:
RegionStoreManager(ProgramStateManager &mgr)
: StoreManager(mgr), RBFactory(mgr.getAllocator()),
CBFactory(mgr.getAllocator()), SmallStructLimit(0), SmallArrayLimit(0) {
ExprEngine &Eng = StateMgr.getOwningEngine();
SmallStructLimit = Options.RegionStoreSmallStructLimit;
SmallArrayLimit = Options.RegionStoreSmallArrayLimit;
}
SVal ArrayToPointer(
Loc Array,
QualType ElementTy)
override;
bool IsMainAnalysis = false;
if (
const auto *FD = dyn_cast<FunctionDecl>(InitLoc->
getDecl()))
IsMainAnalysis = FD->isMain() && !Ctx.getLangOpts().CPlusPlus;
return StoreRef(RegionBindingsRef(
RegionBindingsRef::ParentTy(RBFactory.getEmptyMap(), RBFactory),
CBFactory, IsMainAnalysis).asStore(), *this);
}
RegionBindingsRef invalidateGlobalRegion(MemRegion::Kind K,
unsigned Count,
RegionBindingsRef B,
InvalidatedRegions *Invalidated);
StoreRef invalidateRegions(Store store,
const Expr *
E,
unsigned Count,
const CallEvent *Call,
InvalidatedSymbols &IS,
RegionAndSymbolInvalidationTraits &ITraits,
InvalidatedRegions *Invalidated,
InvalidatedRegions *InvalidatedTopLevel) override;
bool scanReachableSymbols(Store S, const MemRegion *R,
ScanReachableSymbols &Callbacks) override;
const SubRegion *R);
std::optional<SVal>
const ElementRegion *R);
std::optional<SVal>
SVal getSValFromStringLiteral(
const StringLiteral *SL, uint64_t Offset,
public:
StoreRef Bind(Store store,
Loc LV, SVal
V)
override {
return StoreRef(bind(getRegionBindings(store), LV,
V).asStore(), *
this);
}
StoreRef BindDefaultInitial(Store store, const MemRegion *R,
RegionBindingsRef B = getRegionBindings(store);
assert(!(B.getDefaultBinding(R) || B.getDirectBinding(R)) &&
"Double initialization!");
B = B.addBinding(BindingKey::Make(R, BindingKey::Default),
V);
return StoreRef(B.asImmutableMap().getRootWithoutRetain(), *this);
}
StoreRef BindDefaultZero(Store store, const MemRegion *R) override {
if (const auto *BR = dyn_cast<CXXBaseObjectRegion>(R))
if (BR->getDecl()->isEmpty())
return StoreRef(store, *this);
RegionBindingsRef B = getRegionBindings(store);
SVal
V = svalBuilder.makeZeroVal(Ctx.CharTy);
B = removeSubRegionBindings(B, cast<SubRegion>(R));
B = B.addBinding(BindingKey::Make(R, BindingKey::Default),
V);
return StoreRef(B.asImmutableMap().getRootWithoutRetain(), *this);
}
std::optional<RegionBindingsRef>
const RecordDecl *RD, nonloc::LazyCompoundVal LCV);
const TypedValueRegion* R, SVal
V);
const TypedValueRegion* R, SVal
V);
std::optional<RegionBindingsRef>
const ArrayType *AT, nonloc::LazyCompoundVal LCV);
const TypedValueRegion* R,
const TypedRegion *R,
SVal DefaultVal);
StoreRef killBinding(Store ST,
Loc L)
override;
void incrementReferenceCount(Store store) override {
getRegionBindings(store).manualRetain();
}
void decrementReferenceCount(Store store) override {
getRegionBindings(store).manualRelease();
}
bool includedInBindings(Store store, const MemRegion *region) const override;
return getBinding(getRegionBindings(S), L, T);
}
std::optional<SVal> getDefaultBinding(Store S, const MemRegion *R) override {
RegionBindingsRef B = getRegionBindings(S);
return B.getDefaultBinding(R->getBaseRegion());
}
SVal getBindingForLazySymbol(const TypedValueRegion *R);
const TypedValueRegion *R,
SVal getLazyBinding(const SubRegion *LazyBindingRegion,
RegionBindingsRef LazyBinding);
std::optional<SVal>
const MemRegion *superR,
const TypedValueRegion *R,
QualType Ty);
std::pair<Store, const SubRegion *>
const SubRegion *originalRegion);
const SValListTy &getInterestingValues(nonloc::LazyCompoundVal LCV);
SymbolReaper& SymReaper) override;
RegionBindingsRef getRegionBindings(Store store) const {
llvm::PointerIntPair<Store, 1, bool> Ptr;
Ptr.setFromOpaqueValue(const_cast<void *>(store));
return RegionBindingsRef(
CBFactory,
static_cast<const RegionBindings::TreeTy *>(Ptr.getPointer()),
RBFactory.getTreeFactory(),
Ptr.getInt());
}
void printJson(raw_ostream &Out, Store S, const char *NL = "\n",
unsigned int Space = 0, bool IsDot = false) const override;
void iterBindings(Store store, BindingsHandler& f) override {
RegionBindingsRef B = getRegionBindings(store);
for (const auto &[Region, Cluster] : B) {
for (
const auto &[Key,
Value] : Cluster) {
if (!Key.isDirect())
continue;
if (const SubRegion *R = dyn_cast<SubRegion>(Key.getRegion())) {
if (!f.HandleBinding(*
this, store, R,
Value))
return;
}
}
}
}
};
}
std::unique_ptr<StoreManager>
ento::CreateRegionStoreManager(ProgramStateManager &StMgr) {
return std::make_unique<RegionStoreManager>(StMgr);
}
namespace {
enum GlobalsFilterKind {
GFK_None,
GFK_SystemOnly,
GFK_All
};
template <typename DERIVED>
class ClusterAnalysis {
protected:
typedef llvm::DenseMap<const MemRegion *, const ClusterBindings *> ClusterMap;
typedef const MemRegion * WorkListElement;
WorkList WL;
RegionStoreManager &RM;
SValBuilder &svalBuilder;
RegionBindingsRef B;
protected:
return B.lookup(R);
}
bool includeEntireMemorySpace(
const MemRegion *
Base) {
return false;
}
public:
ClusterAnalysis(RegionStoreManager &rm, ProgramStateManager &StateMgr,
: RM(rm), Ctx(StateMgr.getContext()),
svalBuilder(StateMgr.getSValBuilder()), B(
std::move(
b)) {}
RegionBindingsRef getRegionBindings() const { return B; }
bool isVisited(const MemRegion *R) {
return Visited.count(getCluster(R));
}
void GenerateClusters() {
for (RegionBindingsRef::iterator RI = B.begin(), RE = B.end();
RI != RE; ++RI){
const MemRegion *
Base = RI.getKey();
assert(!Cluster.isEmpty() && "Empty clusters should be removed");
static_cast<DERIVED*
>(
this)->VisitAddedToCluster(
Base, Cluster);
if (
static_cast<DERIVED*
>(
this)->includeEntireMemorySpace(
Base))
AddToWorkList(WorkListElement(
Base), &Cluster);
}
}
if (C && !
Visited.insert(C).second)
return false;
return true;
}
bool AddToWorkList(const MemRegion *R) {
return static_cast<DERIVED*>(this)->AddToWorkList(R);
}
void RunWorkList() {
while (!WL.empty()) {
WorkListElement
E = WL.pop_back_val();
const MemRegion *BaseR =
E;
static_cast<DERIVED*>(this)->VisitCluster(BaseR, getCluster(BaseR));
}
}
void VisitAddedToCluster(
const MemRegion *baseR,
const ClusterBindings &C) {}
bool Flag) {
static_cast<DERIVED*>(this)->VisitCluster(BaseR, C);
}
};
}
bool RegionStoreManager::scanReachableSymbols(Store S, const MemRegion *R,
ScanReachableSymbols &Callbacks) {
assert(R == R->getBaseRegion() && "Should only be called for base regions");
RegionBindingsRef B = getRegionBindings(S);
if (!Cluster)
return true;
for (ClusterBindings::iterator RI = Cluster->begin(), RE = Cluster->end();
RI != RE; ++RI) {
if (!Callbacks.scan(RI.getData()))
return false;
}
return true;
}
return FR->getDecl()->getParent()->isUnion();
}
assert(K.hasSymbolicOffset() && "Not implemented for concrete offset keys");
const MemRegion *
Base = K.getConcreteOffsetRegion();
const MemRegion *R = K.getRegion();
if (const FieldRegion *FR = dyn_cast<FieldRegion>(R))
Fields.push_back(FR->getDecl());
R = cast<SubRegion>(R)->getSuperRegion();
}
}
assert(K.hasSymbolicOffset() && "Not implemented for concrete offset keys");
if (Fields.empty())
return true;
ptrdiff_t Delta = FieldsInBindingKey.size() - Fields.size();
if (Delta >= 0)
return std::equal(FieldsInBindingKey.begin() + Delta,
FieldsInBindingKey.end(),
Fields.begin());
else
return std::equal(FieldsInBindingKey.begin(), FieldsInBindingKey.end(),
Fields.begin() - Delta);
}
static void
const SubRegion *Top, BindingKey TopKey,
bool IncludeAllDefaultBindings) {
if (TopKey.hasSymbolicOffset()) {
Top = TopKey.getConcreteOffsetRegion();
TopKey = BindingKey::Make(Top, BindingKey::Default);
}
SVal Extent = Top->getMemRegionManager().getStaticSize(Top, SVB);
if (std::optional<nonloc::ConcreteInt> ExtentCI =
Extent.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt &ExtentInt = ExtentCI->getValue();
assert(ExtentInt.isNonNegative() || ExtentInt.isUnsigned());
Length = ExtentInt.getLimitedValue() * SVB.getContext().getCharWidth();
} else if (const FieldRegion *FR = dyn_cast<FieldRegion>(Top)) {
if (FR->getDecl()->isBitField())
Length = FR->getDecl()->getBitWidthValue(SVB.getContext());
}
for (const auto &StoreEntry : Cluster) {
BindingKey NextKey = StoreEntry.first;
if (NextKey.getRegion() == TopKey.getRegion()) {
if (NextKey.getOffset() > TopKey.getOffset() &&
NextKey.getOffset() - TopKey.getOffset() < Length) {
} else if (NextKey.getOffset() == TopKey.getOffset()) {
if (IncludeAllDefaultBindings || NextKey.isDirect())
}
} else if (NextKey.hasSymbolicOffset()) {
const MemRegion *
Base = NextKey.getConcreteOffsetRegion();
if (Top->isSubRegionOf(
Base) && Top !=
Base) {
if (IncludeAllDefaultBindings || NextKey.isDirect())
}
else if (
const SubRegion *BaseSR = dyn_cast<SubRegion>(
Base)) {
if (BaseSR->isSubRegionOf(Top))
}
}
}
}
static void
const SubRegion *Top, bool IncludeAllDefaultBindings) {
BindingKey::Make(Top, BindingKey::Default),
IncludeAllDefaultBindings);
}
RegionBindingsRef
const SubRegion *Top) {
BindingKey TopKey = BindingKey::Make(Top, BindingKey::Default);
const MemRegion *ClusterHead = TopKey.getBaseRegion();
if (Top == ClusterHead) {
return B.remove(Top);
}
if (!Cluster) {
if (TopKey.hasSymbolicOffset()) {
const SubRegion *Concrete = TopKey.getConcreteOffsetRegion();
return B.addBinding(Concrete, BindingKey::Default, UnknownVal());
}
return B;
}
false);
for (BindingKey Key : llvm::make_first_range(
Bindings))
Result = Result.remove(Key);
if (TopKey.hasSymbolicOffset()) {
const SubRegion *Concrete = TopKey.getConcreteOffsetRegion();
Result = Result.add(BindingKey::Make(Concrete, BindingKey::Default),
UnknownVal());
}
if (Result.isEmpty())
return B.remove(ClusterHead);
return B.add(ClusterHead, Result.asImmutableMap());
}
namespace {
class InvalidateRegionsWorker : public ClusterAnalysis<InvalidateRegionsWorker>
{
unsigned Count;
RegionAndSymbolInvalidationTraits &ITraits;
StoreManager::InvalidatedRegions *Regions;
GlobalsFilterKind GlobalsFilter;
public:
InvalidateRegionsWorker(RegionStoreManager &rm,
ProgramStateManager &stateMgr,
const Expr *ex,
unsigned count,
InvalidatedSymbols &is,
RegionAndSymbolInvalidationTraits &ITraitsIn,
StoreManager::InvalidatedRegions *r,
GlobalsFilterKind GFK)
: ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr,
b),
Ex(ex), Count(count), LCtx(lctx), IS(is), ITraits(ITraitsIn), Regions(r),
GlobalsFilter(GFK) {}
void VisitBinding(SVal
V);
using ClusterAnalysis::AddToWorkList;
bool AddToWorkList(const MemRegion *R);
bool includeEntireMemorySpace(
const MemRegion *
Base);
bool isInitiallyIncludedGlobalRegion(const MemRegion *R);
};
}
bool InvalidateRegionsWorker::AddToWorkList(const MemRegion *R) {
bool doNotInvalidateSuperRegion = ITraits.hasTrait(
R, RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
const MemRegion *BaseR = doNotInvalidateSuperRegion ? R : R->getBaseRegion();
return AddToWorkList(WorkListElement(BaseR), getCluster(BaseR));
}
void InvalidateRegionsWorker::VisitBinding(SVal
V) {
if (SymbolRef Sym =
V.getAsSymbol())
IS.insert(Sym);
if (
const MemRegion *R =
V.getAsRegion()) {
AddToWorkList(R);
return;
}
if (std::optional<nonloc::LazyCompoundVal> LCS =
V.getAs<nonloc::LazyCompoundVal>()) {
for (SVal
V : RM.getInterestingValues(*LCS))
if (!isa<nonloc::LazyCompoundVal>(
V))
return;
}
}
void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR,
bool PreserveRegionsContents =
ITraits.hasTrait(baseR,
RegionAndSymbolInvalidationTraits::TK_PreserveContents);
if (C) {
for (SVal Val : llvm::make_second_range(*C))
VisitBinding(Val);
if (!PreserveRegionsContents)
B = B.remove(baseR);
}
if (const auto *TO = dyn_cast<TypedValueRegion>(baseR)) {
if (const auto *RD = TO->getValueType()->getAsCXXRecordDecl()) {
if (RD->isLambda() && RD->getLambdaCallOperator()->getBody()) {
using namespace ast_matchers;
const char *DeclBind = "DeclBind";
to(
varDecl(hasStaticStorageDuration()).bind(DeclBind)))));
auto Matches =
match(RefToStatic, *RD->getLambdaCallOperator()->getBody(),
RD->getASTContext());
auto *VD = Match.getNodeAs<
VarDecl>(DeclBind);
const VarRegion *ToInvalidate =
RM.getRegionManager().getVarRegion(VD, LCtx);
AddToWorkList(ToInvalidate);
}
}
}
}
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) {
for (auto Var : BR->referenced_vars()) {
const VarRegion *VR = Var.getCapturedRegion();
AddToWorkList(VR);
}
else if (Loc::isLocType(VR->getValueType())) {
SVal
V = RM.getBinding(B, loc::MemRegionVal(VR));
if (std::optional<Loc> L =
V.getAs<
Loc>()) {
if (const MemRegion *LR = L->getAsRegion())
AddToWorkList(LR);
}
}
}
return;
}
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR))
IS.insert(SR->getSymbol());
if (PreserveRegionsContents)
return;
if (Regions)
Regions->push_back(baseR);
if (isa<AllocaRegion, SymbolicRegion>(baseR)) {
svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, Ctx.
IntTy, Count);
B = B.addBinding(baseR, BindingKey::Default,
V);
return;
}
if (!baseR->isBoundable())
return;
const TypedValueRegion *TR = cast<TypedValueRegion>(baseR);
if (isInitiallyIncludedGlobalRegion(baseR)) {
return;
}
DefinedOrUnknownSVal
V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
B = B.addBinding(baseR, BindingKey::Default,
V);
return;
}
bool doNotInvalidateSuperRegion = ITraits.hasTrait(
baseR,
RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion);
if (doNotInvalidateSuperRegion) {
std::optional<uint64_t> NumElements;
NumElements = CAT->getZExtSize();
if (!NumElements)
goto conjure_default;
QualType ElementTy = AT->getElementType();
const RegionOffset &RO = baseR->getAsOffset();
const MemRegion *SuperR = baseR->getBaseRegion();
if (RO.hasSymbolicOffset()) {
if (SuperR)
AddToWorkList(SuperR);
goto conjure_default;
}
uint64_t UpperOffset = LowerOffset + *NumElements * ElemSize;
bool UpperOverflow = UpperOffset < LowerOffset;
if (!SuperR)
goto conjure_default;
if (!C)
goto conjure_default;
for (
const auto &[BK,
V] : *C) {
std::optional<uint64_t> ROffset =
BK.hasSymbolicOffset() ? std::optional<uint64_t>() : BK.getOffset();
if (!ROffset ||
((*ROffset >= LowerOffset && *ROffset < UpperOffset) ||
(UpperOverflow &&
(*ROffset >= LowerOffset || *ROffset < UpperOffset)) ||
(LowerOffset == UpperOffset && *ROffset == LowerOffset))) {
B = B.removeBinding(BK);
const MemRegion *R =
V.getAsRegion();
if (isa_and_nonnull<SymbolicRegion>(R))
}
}
}
conjure_default:
svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
AT->getElementType(), Count);
B = B.addBinding(baseR, BindingKey::Default,
V);
return;
}
DefinedOrUnknownSVal
V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx,
T,Count);
assert(SymbolManager::canSymbolicate(T) ||
V.isUnknown());
B = B.addBinding(baseR, BindingKey::Direct,
V);
}
bool InvalidateRegionsWorker::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");
}
bool InvalidateRegionsWorker::includeEntireMemorySpace(
const MemRegion *
Base) {
if (isInitiallyIncludedGlobalRegion(
Base))
return true;
const MemSpaceRegion *MemSpace =
Base->getMemorySpace();
return ITraits.hasTrait(MemSpace,
RegionAndSymbolInvalidationTraits::TK_EntireMemSpace);
}
RegionBindingsRef
RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K,
unsigned Count,
RegionBindingsRef B,
InvalidatedRegions *Invalidated) {
const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(K);
SVal
V = svalBuilder.conjureSymbolVal( (
const void*) GS, Ex, LCtx,
Count);
B = B.removeBinding(GS)
.addBinding(BindingKey::Make(GS, BindingKey::Default),
V);
if (Invalidated)
Invalidated->push_back(GS);
return B;
}
void RegionStoreManager::populateWorkList(InvalidateRegionsWorker &W,
InvalidatedRegions *TopLevelRegions) {
if (
auto LCS =
V.getAs<nonloc::LazyCompoundVal>()) {
for (SVal S : getInterestingValues(*LCS))
if (const MemRegion *R = S.getAsRegion())
W.AddToWorkList(R);
continue;
}
if (
const MemRegion *R =
V.getAsRegion()) {
if (TopLevelRegions)
TopLevelRegions->push_back(R);
W.AddToWorkList(R);
continue;
}
}
}
StoreRef
RegionStoreManager::invalidateRegions(Store store,
const Expr *Ex,
unsigned Count,
const CallEvent *Call,
InvalidatedSymbols &IS,
RegionAndSymbolInvalidationTraits &ITraits,
InvalidatedRegions *TopLevelRegions,
InvalidatedRegions *Invalidated) {
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, ITraits,
Invalidated, GlobalsFilter);
W.GenerateClusters();
populateWorkList(W, Values, TopLevelRegions);
W.RunWorkList();
B = W.getRegionBindings();
switch (GlobalsFilter) {
case GFK_All:
B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind,
Ex, Count, LCtx, B, Invalidated);
[[fallthrough]];
case GFK_SystemOnly:
B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind,
Ex, Count, LCtx, B, Invalidated);
[[fallthrough]];
case GFK_None:
break;
}
return StoreRef(B.asStore(), *this);
}
SVal RegionStoreManager::ArrayToPointer(
Loc Array,
QualType T) {
if (isa<loc::ConcreteInt>(Array))
return Array;
if (!isa<loc::MemRegionVal>(Array))
return UnknownVal();
const SubRegion *R =
cast<SubRegion>(Array.castAs<loc::MemRegionVal>().getRegion());
NonLoc ZeroIdx = svalBuilder.makeZeroArrayIndex();
return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, R, Ctx));
}
assert(!isa<UnknownVal>(L) && "location unknown");
assert(!isa<UndefinedVal>(L) && "location undefined");
if (L.getAs<loc::ConcreteInt>()) {
return UnknownVal();
}
if (!L.getAs<loc::MemRegionVal>()) {
return UnknownVal();
}
const MemRegion *MR = L.castAs<loc::MemRegionVal>().
getRegion();
if (isa<BlockDataRegion>(MR)) {
return UnknownVal();
}
if (const auto *TVR = dyn_cast<TypedValueRegion>(MR))
else if (const auto *TR = dyn_cast<TypedRegion>(MR))
else if (const auto *SR = dyn_cast<SymbolicRegion>(MR))
T = SR->getPointeeStaticType();
}
assert(!
T.isNull() &&
"Unable to auto-detect binding type!");
assert(!
T->
isVoidType() &&
"Attempting to dereference a void pointer!");
if (!isa<TypedValueRegion>(MR))
MR = GetElementZeroRegion(cast<SubRegion>(MR), T);
const TypedValueRegion *R = cast<TypedValueRegion>(MR);
return UnknownVal();
return getBindingForStruct(B, R);
return createLazyBinding(B, R);
return getBindingForArray(B, R);
else
return UnknownVal();
}
return UnknownVal();
if (const FieldRegion* FR = dyn_cast<FieldRegion>(R))
return svalBuilder.evalCast(getBindingForField(B, FR), T,
QualType{});
if (const ElementRegion* ER = dyn_cast<ElementRegion>(R)) {
return svalBuilder.evalCast(getBindingForElement(B, ER), T,
QualType{});
}
if (const ObjCIvarRegion *IVR = dyn_cast<ObjCIvarRegion>(R)) {
return svalBuilder.evalCast(getBindingForObjCIvar(B, IVR), T,
QualType{});
}
if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
return svalBuilder.evalCast(getBindingForVar(B, VR), T,
QualType{});
}
const SVal *
V = B.lookup(R, BindingKey::Direct);
if (R->hasStackNonParametersStorage()) {
return UndefinedVal();
}
return svalBuilder.getRegionValueSymbolVal(R);
}
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;
}
static std::optional<nonloc::LazyCompoundVal>
const SubRegion *R, bool AllowSubregionBindings) {
std::optional<SVal>
V = B.getDefaultBinding(R);
return std::nullopt;
std::optional<nonloc::LazyCompoundVal> LCV =
V->getAs<nonloc::LazyCompoundVal>();
if (!LCV)
return std::nullopt;
QualType SourceRegionTy = LCV->getRegion()->getValueType();
if (!SVB.getContext().hasSameUnqualifiedType(RegionTy, SourceRegionTy))
return std::nullopt;
}
if (!AllowSubregionBindings) {
true);
return std::nullopt;
}
return *LCV;
}
std::pair<Store, const SubRegion *>
const SubRegion *R,
const SubRegion *originalRegion) {
if (originalRegion != R) {
if (std::optional<nonloc::LazyCompoundVal>
V =
return std::make_pair(
V->getStore(),
V->getRegion());
}
typedef std::pair<Store, const SubRegion *> StoreRegionPair;
StoreRegionPair Result = StoreRegionPair();
if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
Result = findLazyBinding(B, cast<SubRegion>(ER->getSuperRegion()),
originalRegion);
if (Result.second)
Result.second = MRMgr.getElementRegionWithSuper(ER, Result.second);
} else if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) {
Result = findLazyBinding(B, cast<SubRegion>(FR->getSuperRegion()),
originalRegion);
if (Result.second)
Result.second = MRMgr.getFieldRegionWithSuper(FR, Result.second);
} else if (const CXXBaseObjectRegion *BaseReg =
dyn_cast<CXXBaseObjectRegion>(R)) {
Result = findLazyBinding(B, cast<SubRegion>(BaseReg->getSuperRegion()),
originalRegion);
if (Result.second)
Result.second = MRMgr.getCXXBaseObjectRegionWithSuper(BaseReg,
Result.second);
}
return Result;
}
assert(CAT && "ConstantArrayType should not be null");
do {
return Extents;
}
static std::pair<SmallVector<SVal, 2>, const MemRegion *>
assert(ER && "ConstantArrayType should not be null");
do {
SValOffsets.push_back(ER->getIndex());
Base = ER->getSuperRegion();
ER = dyn_cast<ElementRegion>(
Base);
} while (ER);
return {SValOffsets,
Base};
}
static std::optional<SVal>
DstOffsets.resize(SrcOffsets.size());
auto ExtentIt = ArrayExtents.begin();
auto OffsetIt = DstOffsets.begin();
for (SVal
V : llvm::reverse(SrcOffsets)) {
if (
auto CI =
V.getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt &Offset = CI->getValue();
if (Offset.isNegative() || Offset.uge(*(ExtentIt++)))
return UndefinedVal();
*(OffsetIt++) = Offset.getZExtValue();
continue;
}
return UnknownVal();
}
return std::nullopt;
}
std::optional<SVal> RegionStoreManager::getConstantValFromConstArrayInitializer(
assert(R && "ElementRegion should not be null");
const VarRegion *VR = dyn_cast<VarRegion>(
Base);
if (!VR)
return std::nullopt;
assert(!SValOffsets.empty() && "getElementRegionOffsets guarantees the "
"offsets vector is not empty.");
!R->getElementType().isConstQualified() &&
return std::nullopt;
if (!Init)
return std::nullopt;
if (!CAT)
return std::nullopt;
if (SValOffsets.size() != Extents.size())
return std::nullopt;
SValOffsets, Extents, ConcreteOffsets))
if (const auto *ILE = dyn_cast<InitListExpr>(Init))
return getSValFromInitListExpr(ILE, ConcreteOffsets, R->getElementType());
if (const auto *SL = dyn_cast<StringLiteral>(Init))
return getSValFromStringLiteral(SL, ConcreteOffsets.front(),
R->getElementType());
return std::nullopt;
}
std::optional<SVal> RegionStoreManager::getSValFromInitListExpr(
assert(ILE && "InitListExpr should not be null");
for (uint64_t Offset : Offsets) {
if (
const auto *SL = dyn_cast<StringLiteral>(ILE->
getInit(0)))
return getSValFromStringLiteral(SL, Offset, ElemT);
return svalBuilder.makeZeroVal(ElemT);
const auto *IL = dyn_cast<InitListExpr>(
E);
if (!IL)
return svalBuilder.getConstantVal(
E);
ILE = IL;
}
assert(ILE);
return std::nullopt;
}
SVal RegionStoreManager::getSValFromStringLiteral(
const StringLiteral *SL,
uint64_t Offset,
assert(SL && "StringLiteral should not be null");
return svalBuilder.makeIntVal(Code, ElemT);
}
const TypedValueRegion *SubReg,
const ASTContext &Ctx, SValBuilder &SVB) {
assert(BaseRegion);
QualType BaseTy = BaseRegion->getValueType();
if (const std::optional<SVal> &ParentValue =
B.getDirectBinding(BaseRegion)) {
if (SymbolRef ParentValueAsSym = ParentValue->getAsSymbol())
return SVB.getDerivedRegionValueSymbolVal(ParentValueAsSym, SubReg);
if (ParentValue->isUndef())
return UndefinedVal();
return UnknownVal();
}
}
}
return std::nullopt;
}
const ElementRegion* R) {
if (
const std::optional<SVal> &
V = B.getDirectBinding(R))
const MemRegion* superR = R->getSuperRegion();
if (const StringRegion *StrR = dyn_cast<StringRegion>(superR)) {
return UnknownVal();
if (const auto CI = R->getIndex().getAs<nonloc::ConcreteInt>()) {
const llvm::APSInt &Idx = CI->getValue();
if (Idx < 0)
return UndefinedVal();
return getSValFromStringLiteral(SL, Idx.getZExtValue(), T);
}
} else if (isa<ElementRegion, VarRegion>(superR)) {
if (std::optional<SVal>
V = getConstantValFromConstArrayInitializer(B, R))
}
if (isa<CodeTextRegion>(superR))
return UnknownVal();
const RegionRawOffset &O = R->getAsArrayOffset();
if (!O.getRegion())
return UnknownVal();
if (const TypedValueRegion *baseR = dyn_cast<TypedValueRegion>(O.getRegion()))
return getBindingForFieldOrElementCommon(B, R, R->getElementType());
}
const FieldRegion* R) {
if (
const std::optional<SVal> &
V = B.getDirectBinding(R))
const MemRegion* superR = R->getSuperRegion();
if (const auto *VR = dyn_cast<VarRegion>(superR)) {
if (const auto *InitList = dyn_cast<InitListExpr>(Init)) {
if (Index < InitList->getNumInits()) {
if (
const Expr *FieldInit = InitList->getInit(Index))
if (std::optional<SVal>
V = svalBuilder.getConstantVal(FieldInit))
} else {
return svalBuilder.makeZeroVal(Ty);
}
}
}
if (
const auto *
Base = dyn_cast<TypedValueRegion>(R->getBaseRegion()))
return getBindingForFieldOrElementCommon(B, R, Ty);
}
std::optional<SVal> RegionStoreManager::getBindingForDerivedDefaultValue(
const TypedValueRegion *R,
QualType Ty) {
if (
const std::optional<SVal> &
D = B.getDefaultBinding(superR)) {
if (SymbolRef parentSym = val.getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
if (val.isZeroConstant())
return svalBuilder.makeZeroVal(Ty);
if (val.isUnknownOrUndef())
return val;
if (isa<nonloc::LazyCompoundVal, nonloc::CompoundVal>(val))
return val;
llvm_unreachable("Unknown default value");
}
return std::nullopt;
}
SVal RegionStoreManager::getLazyBinding(const SubRegion *LazyBindingRegion,
RegionBindingsRef LazyBinding) {
SVal Result;
if (const ElementRegion *ER = dyn_cast<ElementRegion>(LazyBindingRegion))
Result = getBindingForElement(LazyBinding, ER);
else
Result = getBindingForField(LazyBinding,
cast<FieldRegion>(LazyBindingRegion));
if (Result.isUndef())
Result = UnknownVal();
return Result;
}
SVal
const TypedValueRegion *R,
Store lazyBindingStore =
nullptr;
const SubRegion *lazyBindingRegion = nullptr;
std::tie(lazyBindingStore, lazyBindingRegion) = findLazyBinding(B, R, R);
if (lazyBindingRegion)
return getLazyBinding(lazyBindingRegion,
getRegionBindings(lazyBindingStore));
bool hasSymbolicIndex = false;
bool hasPartialLazyBinding = false;
const SubRegion *SR = R;
while (SR) {
const MemRegion *
Base = SR->getSuperRegion();
if (std::optional<SVal>
D =
getBindingForDerivedDefaultValue(B,
Base, R, Ty)) {
if (
D->getAs<nonloc::LazyCompoundVal>()) {
hasPartialLazyBinding = true;
break;
}
}
if (
const ElementRegion *ER = dyn_cast<ElementRegion>(
Base)) {
NonLoc index = ER->getIndex();
if (!index.isConstant())
hasSymbolicIndex = true;
}
SR = dyn_cast<SubRegion>(
Base);
}
if (R->hasStackNonParametersStorage()) {
if (isa<ElementRegion>(R)) {
if (const TypedValueRegion *typedSuperR =
dyn_cast<TypedValueRegion>(R->getSuperRegion())) {
if (typedSuperR->getValueType()->isVectorType())
return UnknownVal();
}
}
if (hasSymbolicIndex)
return UnknownVal();
if (!hasPartialLazyBinding && !isa<BlockDataRegion>(R->getBaseRegion())) {
if (
const std::optional<SVal> &
V = B.getDefaultBinding(R))
return UndefinedVal();
}
}
return svalBuilder.getRegionValueSymbolVal(R);
}
const ObjCIvarRegion* R) {
if (
const std::optional<SVal> &
V = B.getDirectBinding(R))
const MemRegion *superR = R->getSuperRegion();
if (
const std::optional<SVal> &
V = B.getDefaultBinding(superR)) {
if (SymbolRef parentSym =
V->getAsSymbol())
return svalBuilder.getDerivedRegionValueSymbolVal(parentSym, R);
return UnknownVal();
}
return getBindingForLazySymbol(R);
}
const VarRegion *R) {
if (std::optional<SVal>
V = B.getDirectBinding(R))
if (std::optional<SVal>
V = B.getDefaultBinding(R))
const MemSpaceRegion *MS = R->getMemorySpace();
if (isa<StackArgumentsSpaceRegion>(MS))
return svalBuilder.getRegionValueSymbolVal(R);
if (std::optional<SVal>
V = svalBuilder.getConstantVal(Init))
return UnknownVal();
}
}
if (isa<UnknownSpaceRegion>(MS))
return svalBuilder.getRegionValueSymbolVal(R);
if (isa<GlobalsSpaceRegion>(MS)) {
if (B.isMainAnalysis())
if (std::optional<SVal>
V = svalBuilder.getConstantVal(Init))
if (isa<StaticGlobalSpaceRegion>(MS))
return svalBuilder.makeZeroVal(T);
if (std::optional<SVal>
V = getBindingForDerivedDefaultValue(B, MS, R, T)) {
assert(!
V->getAs<nonloc::LazyCompoundVal>());
}
return svalBuilder.getRegionValueSymbolVal(R);
}
return UndefinedVal();
}
SVal RegionStoreManager::getBindingForLazySymbol(const TypedValueRegion *R) {
return svalBuilder.getRegionValueSymbolVal(R);
}
const RegionStoreManager::SValListTy &
RegionStoreManager::getInterestingValues(nonloc::LazyCompoundVal LCV) {
LazyBindingsMapTy::iterator I = LazyBindingsMap.find(LCV.getCVData());
if (I != LazyBindingsMap.end())
return I->second;
SValListTy List;
const SubRegion *LazyR = LCV.getRegion();
RegionBindingsRef B = getRegionBindings(LCV.getStore());
if (!Cluster)
return (LazyBindingsMap[LCV.getCVData()] = std::move(List));
true);
for (SVal
V : llvm::make_second_range(
Bindings)) {
if (
V.isUnknownOrUndef() ||
V.isConstant())
continue;
if (
auto InnerLCV =
V.getAs<nonloc::LazyCompoundVal>()) {
const SValListTy &InnerList = getInterestingValues(*InnerLCV);
List.insert(List.end(), InnerList.begin(), InnerList.end());
}
}
return (LazyBindingsMap[LCV.getCVData()] = std::move(List));
}
const TypedValueRegion *R) {
if (std::optional<nonloc::LazyCompoundVal>
V =
return svalBuilder.makeLazyCompoundVal(StoreRef(B.asStore(), *this), R);
}
return false;
return CRD->getNumBases() == 0;
return true;
}
const TypedValueRegion *R) {
return UnknownVal();
return createLazyBinding(B, R);
}
const TypedValueRegion *R) {
"Only constant array types can have compound bindings.");
return createLazyBinding(B, R);
}
bool RegionStoreManager::includedInBindings(Store store,
const MemRegion *region) const {
RegionBindingsRef B = getRegionBindings(store);
region = region->getBaseRegion();
if (B.lookup(region))
return true;
for (RegionBindingsRef::iterator RI = B.begin(), RE = B.end(); RI != RE; ++RI) {
for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end();
CI != CE; ++CI) {
if (
const MemRegion *R =
D.getAsRegion())
if (R->getBaseRegion() == region)
return true;
}
}
return false;
}
StoreRef RegionStoreManager::killBinding(Store ST,
Loc L) {
if (std::optional<loc::MemRegionVal> LV = L.getAs<loc::MemRegionVal>())
if (const MemRegion* R = LV->getRegion())
return StoreRef(getRegionBindings(ST).removeBinding(R)
.asImmutableMap()
.getRootWithoutRetain(),
*this);
return StoreRef(ST, *this);
}
RegionBindingsRef
auto MemRegVal = L.getAs<loc::MemRegionVal>();
if (!MemRegVal)
return B;
const MemRegion *R = MemRegVal->getRegion();
if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) {
return bindArray(B, TR,
V);
return bindStruct(B, TR,
V);
return bindVector(B, TR,
V);
return bindAggregate(B, TR,
V);
}
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
R = GetElementZeroRegion(SR, SR->getPointeeStaticType());
assert((!isa<CXXThisRegion>(R) || !B.lookup(R)) &&
"'this' pointer is not an l-value and is not assignable");
RegionBindingsRef NewB = removeSubRegionBindings(B, cast<SubRegion>(R));
auto KeyKind = isa<nonloc::LazyCompoundVal>(
V) ? BindingKey::Default
: BindingKey::Direct;
return NewB.addBinding(BindingKey::Make(R, KeyKind),
V);
}
RegionBindingsRef
const MemRegion *R,
if (Loc::isLocType(T))
V = svalBuilder.makeNullWithType(T);
V = svalBuilder.makeZeroVal(T);
V = svalBuilder.makeZeroVal(Ctx.
IntTy);
}
else {
assert(!SymbolManager::canSymbolicate(T) && "This type is representable");
}
return B.addBinding(R, BindingKey::Default,
V);
}
std::optional<RegionBindingsRef> RegionStoreManager::tryBindSmallArray(
nonloc::LazyCompoundVal LCV) {
auto CAT = dyn_cast<ConstantArrayType>(AT);
if (!CAT)
return std::nullopt;
return std::nullopt;
if (ArrSize > SmallArrayLimit)
return std::nullopt;
RegionBindingsRef NewB = B;
for (uint64_t i = 0; i < ArrSize; ++i) {
auto Idx = svalBuilder.makeArrayIndex(i);
const ElementRegion *SrcER =
MRMgr.getElementRegion(Ty, Idx, LCV.getRegion(), Ctx);
SVal
V = getBindingForElement(getRegionBindings(LCV.getStore()), SrcER);
const ElementRegion *DstER = MRMgr.getElementRegion(Ty, Idx, R, Ctx);
NewB = bind(NewB, loc::MemRegionVal(DstER),
V);
}
return NewB;
}
RegionBindingsRef
const TypedValueRegion* R,
SVal Init) {
std::optional<uint64_t>
Size;
if (std::optional<loc::MemRegionVal> MRV =
Init.getAs<loc::MemRegionVal>()) {
SVal
V = getBinding(B.asStore(), *MRV, R->getValueType());
return bindAggregate(B, R,
V);
}
if (std::optional<nonloc::LazyCompoundVal> LCV =
Init.getAs<nonloc::LazyCompoundVal>()) {
if (std::optional<RegionBindingsRef> NewB =
tryBindSmallArray(B, R, AT, *LCV))
return *NewB;
return bindAggregate(B, R, Init);
}
return bindAggregate(B, R, UnknownVal());
const nonloc::CompoundVal& CV =
Init.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
RegionBindingsRef NewB(B);
for (;
Size ? i < *
Size :
true; ++i, ++VI) {
if (VI == VE)
break;
NonLoc Idx = svalBuilder.makeArrayIndex(i);
const ElementRegion *ER = MRMgr.getElementRegion(ElementTy, Idx, R, Ctx);
NewB = bindStruct(NewB, ER, *VI);
NewB = bindArray(NewB, ER, *VI);
else
NewB = bind(NewB, loc::MemRegionVal(ER), *VI);
}
if (!Size || i < *Size)
NewB = setImplicitDefaultValue(NewB, R, ElementTy);
return NewB;
}
const TypedValueRegion* R,
if (isa<nonloc::LazyCompoundVal, nonloc::SymbolVal>(
V))
return bindAggregate(B, R,
V);
if (!isa<nonloc::CompoundVal>(
V)) {
return bindAggregate(B, R, UnknownVal());
}
nonloc::CompoundVal CV =
V.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
RegionBindingsRef NewB(B);
for ( ; index != numElements ; ++index) {
if (VI == VE)
break;
NonLoc Idx = svalBuilder.makeArrayIndex(index);
const ElementRegion *ER = MRMgr.getElementRegion(ElemType, Idx, R, Ctx);
NewB = bindArray(NewB, ER, *VI);
NewB = bindStruct(NewB, ER, *VI);
else
NewB = bind(NewB, loc::MemRegionVal(ER), *VI);
}
return NewB;
}
std::optional<RegionBindingsRef> RegionStoreManager::tryBindSmallStruct(
nonloc::LazyCompoundVal LCV) {
if (
Class->getNumBases() != 0 ||
Class->getNumVBases() != 0)
return std::nullopt;
for (
const auto *FD : RD->
fields()) {
continue;
if (Fields.size() == SmallStructLimit)
return std::nullopt;
continue;
return std::nullopt;
Fields.push_back(FD);
}
RegionBindingsRef NewB = B;
const FieldRegion *SourceFR = MRMgr.getFieldRegion(Field, LCV.getRegion());
SVal
V = getBindingForField(getRegionBindings(LCV.getStore()), SourceFR);
const FieldRegion *DestFR = MRMgr.getFieldRegion(Field, R);
NewB = bind(NewB, loc::MemRegionVal(DestFR),
V);
}
return NewB;
}
const TypedValueRegion *R,
if (!RD->isCompleteDefinition())
return B;
if (std::optional<nonloc::LazyCompoundVal> LCV =
V.getAs<nonloc::LazyCompoundVal>()) {
if (std::optional<RegionBindingsRef> NewB =
tryBindSmallStruct(B, R, RD, *LCV))
return *NewB;
return bindAggregate(B, R,
V);
}
if (isa<nonloc::SymbolVal>(
V))
return bindAggregate(B, R,
V);
if (
V.isUnknown() || !isa<nonloc::CompoundVal>(
V))
return bindAggregate(B, R, UnknownVal());
const nonloc::CompoundVal& CV =
V.castAs<nonloc::CompoundVal>();
nonloc::CompoundVal::iterator VI = CV.begin(), VE = CV.end();
RegionBindingsRef NewB(B);
if (const auto *CRD = dyn_cast<CXXRecordDecl>(RD)) {
assert((CRD->isAggregate() || (Ctx.
getLangOpts().ObjC && VI == VE)) &&
"Non-aggregates are constructed with a constructor!");
for (const auto &B : CRD->bases()) {
assert(!B.isVirtual() && "Aggregates cannot have virtual base classes!");
if (VI == VE)
break;
assert(BRD && "Base classes must be C++ classes!");
const CXXBaseObjectRegion *BR =
MRMgr.getCXXBaseObjectRegion(BRD, R, false);
NewB = bindStruct(NewB, BR, *VI);
++VI;
}
}
for (FI = RD->field_begin(), FE = RD->field_end(); FI != FE; ++FI) {
if (VI == VE)
break;
if (FI->isUnnamedBitField())
continue;
const FieldRegion* FR = MRMgr.getFieldRegion(*FI, R);
NewB = bindArray(NewB, FR, *VI);
NewB = bindStruct(NewB, FR, *VI);
else
NewB = bind(NewB, loc::MemRegionVal(FR), *VI);
++VI;
}
if (FI != FE) {
NewB = NewB.addBinding(R, BindingKey::Default,
svalBuilder.makeIntVal(0, false));
}
return NewB;
}
RegionBindingsRef
const TypedRegion *R,
SVal Val) {
return removeSubRegionBindings(B, R).addBinding(R, BindingKey::Default, Val);
}
namespace {
class RemoveDeadBindingsWorker
: public ClusterAnalysis<RemoveDeadBindingsWorker> {
SymbolReaper &SymReaper;
public:
RemoveDeadBindingsWorker(RegionStoreManager &rm,
ProgramStateManager &stateMgr,
RegionBindingsRef
b, SymbolReaper &symReaper,
: ClusterAnalysis<RemoveDeadBindingsWorker>(rm, stateMgr,
b),
SymReaper(symReaper), CurrentLCtx(LCtx) {}
void VisitAddedToCluster(
const MemRegion *baseR,
const ClusterBindings &C);
using ClusterAnalysis<RemoveDeadBindingsWorker>::VisitCluster;
using ClusterAnalysis::AddToWorkList;
bool AddToWorkList(const MemRegion *R);
bool UpdatePostponed();
void VisitBinding(SVal
V);
};
}
bool RemoveDeadBindingsWorker::AddToWorkList(const MemRegion *R) {
const MemRegion *BaseR = R->getBaseRegion();
return AddToWorkList(WorkListElement(BaseR), getCluster(BaseR));
}
void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR,
if (const VarRegion *VR = dyn_cast<VarRegion>(baseR)) {
if (SymReaper.isLive(VR))
AddToWorkList(baseR, &C);
return;
}
if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) {
if (SymReaper.isLive(SR->getSymbol()))
AddToWorkList(SR, &C);
else
Postponed.push_back(SR);
return;
}
if (isa<NonStaticGlobalSpaceRegion>(baseR)) {
AddToWorkList(baseR, &C);
return;
}
if (const CXXThisRegion *TR = dyn_cast<CXXThisRegion>(baseR)) {
const auto *StackReg =
cast<StackArgumentsSpaceRegion>(TR->getSuperRegion());
if (CurrentLCtx &&
(RegCtx == CurrentLCtx || RegCtx->
isParentOf(CurrentLCtx)))
AddToWorkList(TR, &C);
}
}
void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR,
if (!C)
return;
if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR))
SymReaper.markLive(SymR->getSymbol());
for (const auto &[Key, Val] : *C) {
SymReaper.markElementIndicesLive(Key.getRegion());
VisitBinding(Val);
}
}
void RemoveDeadBindingsWorker::VisitBinding(SVal
V) {
if (
auto LCS =
V.getAs<nonloc::LazyCompoundVal>()) {
SymReaper.markLazilyCopied(LCS->getRegion());
for (SVal
V : RM.getInterestingValues(*LCS)) {
if (
auto DepLCS =
V.getAs<nonloc::LazyCompoundVal>())
SymReaper.markLazilyCopied(DepLCS->getRegion());
else
}
return;
}
if (
const MemRegion *R =
V.getAsRegion()) {
AddToWorkList(R);
SymReaper.markLive(R);
if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
for (auto Var : BR->referenced_vars())
AddToWorkList(Var.getCapturedRegion());
}
}
for (SymbolRef Sym :
V.symbols())
SymReaper.markLive(Sym);
}
bool RemoveDeadBindingsWorker::UpdatePostponed() {
for (const SymbolicRegion *SR : Postponed) {
if (SymReaper.isLive(SR->getSymbol())) {
SR = nullptr;
}
}
}
StoreRef RegionStoreManager::removeDeadBindings(Store store,
SymbolReaper& SymReaper) {
RegionBindingsRef B = getRegionBindings(store);
RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, LCtx);
W.GenerateClusters();
for (const MemRegion *Reg : SymReaper.regions()) {
W.AddToWorkList(Reg);
}
do W.RunWorkList(); while (W.UpdatePostponed());
for (
const MemRegion *
Base : llvm::make_first_range(B)) {
}
return StoreRef(B.asStore(), *this);
}
void RegionStoreManager::printJson(raw_ostream &Out, Store S, const char *NL,
unsigned int Space, bool IsDot) const {
RegionBindingsRef
Bindings = getRegionBindings(S);
Indent(Out, Space, IsDot) << "\"store\": ";
Out << "null," << NL;
return;
}
Out <<
"{ \"pointer\": \"" <<
Bindings.asStore() <<
"\", \"items\": [" << NL;
Bindings.printJson(Out, NL, Space + 1, IsDot);
Indent(Out, Space, IsDot) << "]}," << NL;
}
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
static const MemRegion * getRegion(const CallEvent &Call, const MutexDescriptor &Descriptor, bool IsLock)
enum clang::sema::@1658::IndirectLocalPathEntry::EntryKind Kind
static void dump(llvm::raw_ostream &OS, StringRef FunctionName, ArrayRef< CounterExpression > Expressions, ArrayRef< CounterMappingRegion > Regions)
llvm::DenseSet< const void * > Visited
static std::optional< SVal > convertOffsetsFromSvalToUnsigneds(const SmallVector< SVal, 2 > &SrcOffsets, const SmallVector< uint64_t, 2 > ArrayExtents, SmallVector< uint64_t, 2 > &DstOffsets)
llvm::ImmutableMap< const MemRegion *, ClusterBindings > RegionBindings
static std::optional< SVal > getDerivedSymbolForBinding(RegionBindingsConstRef B, const TypedValueRegion *BaseRegion, const TypedValueRegion *SubReg, const ASTContext &Ctx, SValBuilder &SVB)
std::pair< BindingKey, SVal > BindingPair
static bool isCompatibleWithFields(BindingKey K, const FieldVector &Fields)
static bool isRecordEmpty(const RecordDecl *RD)
SmallVector< const FieldDecl *, 8 > FieldVector
llvm::ImmutableMap< BindingKey, SVal > ClusterBindings
static bool isUnionField(const FieldRegion *FR)
static void getSymbolicOffsetFields(BindingKey K, FieldVector &Fields)
static QualType getUnderlyingType(const SubRegion *R)
llvm::ImmutableMapRef< BindingKey, SVal > ClusterBindingsRef
static SmallVector< uint64_t, 2 > getConstantArrayExtents(const ConstantArrayType *CAT)
This is a helper function for getConstantValFromConstArrayInitializer.
static std::pair< SmallVector< SVal, 2 >, const MemRegion * > getElementRegionOffsetsWithBase(const ElementRegion *ER)
This is a helper function for getConstantValFromConstArrayInitializer.
const RegionBindingsRef & RegionBindingsConstRef
static std::optional< nonloc::LazyCompoundVal > getExistingLazyBinding(SValBuilder &SVB, RegionBindingsConstRef B, const SubRegion *R, bool AllowSubregionBindings)
Checks to see if store B has a lazy binding for region R.
static void collectSubRegionBindings(SmallVectorImpl< BindingPair > &Bindings, SValBuilder &SVB, const ClusterBindings &Cluster, const SubRegion *Top, BindingKey TopKey, bool IncludeAllDefaultBindings)
Collects all bindings in Cluster that may refer to bindings within Top.
llvm::SmallVector< std::pair< const MemRegion *, SVal >, 4 > Bindings
__PTRDIFF_TYPE__ ptrdiff_t
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const ConstantArrayType * getAsConstantArrayType(QualType T) const
CanQualType getCanonicalType(QualType T) const
Return the canonical (structural) type corresponding to the specified potentially non-canonical type ...
const LangOptions & getLangOpts() const
bool hasSameUnqualifiedType(QualType T1, QualType T2) const
Determine whether the given types are equivalent after cvr-qualifiers have been removed.
const ArrayType * getAsArrayType(QualType T) const
Type Query functions.
uint64_t getTypeSize(QualType T) const
Return the size of the specified (complete) type T, in bits.
CharUnits getTypeSizeInChars(QualType T) const
Return the size of the specified (complete) type T, in characters.
uint64_t getConstantArrayElementCount(const ConstantArrayType *CA) const
Return number of constant array elements.
Stores options for the analyzer from the command line.
Represents an array type, per C99 6.7.5.2 - Array Declarators.
QualType getElementType() const
Represents a C++ struct/union/class.
Represents the canonical version of C arrays with a specified constant size.
uint64_t getLimitedSize() const
Return the size zero-extended to uint64_t or UINT64_MAX if the value is larger than UINT64_MAX.
uint64_t getZExtSize() const
Return the size zero-extended as a uint64_t.
specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext,...
This represents one expression.
Represents a member of a struct/union/class.
unsigned getFieldIndex() const
Returns the index of this field within its record, as appropriate for passing to ASTRecordLayout::get...
bool isUnnamedBitField() const
Determines whether this is an unnamed bitfield.
Describes an C or C++ initializer list.
bool isStringLiteralInit() const
Is this an initializer for an array of characters, initialized by a string literal or an @encode?
unsigned getNumInits() const
const Expr * getInit(unsigned Init) const
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
bool isParentOf(const LocationContext *LC) const
const Decl * getDecl() const
const StackFrameContext * getStackFrame() const
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
bool isConstQualified() const
Determine whether this type is const-qualified.
Represents a struct/union/class.
field_range fields() const
RecordDecl * getDefinition() const
Returns the RecordDecl that actually defines this struct/union/class.
A helper class that allows the use of isa/cast/dyncast to detect TagType objects of structs/unions/cl...
RecordDecl * getDecl() const
It represents a stack frame of the call stack (based on CallEvent).
StringLiteral - This represents a string literal expression, e.g.
unsigned getLength() const
uint32_t getCodeUnit(size_t i) const
CXXRecordDecl * getAsCXXRecordDecl() const
Retrieves the CXXRecordDecl that this type refers to, either because the type is a RecordType or beca...
bool isConstantArrayType() const
bool isVoidPointerType() const
const T * castAs() const
Member-template castAs<specific type>.
bool isReferenceType() const
bool isScalarType() const
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
bool isIntegralOrEnumerationType() const
Determine whether this type is an integral or enumeration type.
bool isAnyComplexType() const
QualType getCanonicalTypeInternal() const
bool isStructureOrClassType() const
bool isVectorType() const
bool isRecordType() const
Represents a variable declaration or definition.
bool hasGlobalStorage() const
Returns true for all variables that do not have local storage.
bool hasLocalStorage() const
Returns true if a variable with function scope is a non-static local variable.
const Expr * getAnyInitializer() const
Get the initializer for this variable, no matter which declaration it is attached to.
Represents a GCC generic vector type.
unsigned getNumElements() const
QualType getElementType() const
Maps string IDs to AST nodes matched by parts of a matcher.
Defines the clang::TargetInfo interface.
const internal::VariadicDynCastAllOfMatcher< Decl, VarDecl > varDecl
Matches variable declarations.
const internal::VariadicDynCastAllOfMatcher< Stmt, DeclRefExpr > declRefExpr
Matches expressions that refer to declarations.
const internal::ArgumentAdaptingMatcherFunc< internal::HasDescendantMatcher > hasDescendant
Matches AST nodes that have descendant AST nodes that match the provided matcher.
SmallVector< BoundNodes, 1 > match(MatcherT Matcher, const NodeT &Node, ASTContext &Context)
Returns the results of matching Matcher on Node.
internal::Matcher< Stmt > StatementMatcher
const internal::VariadicAllOfMatcher< Stmt > stmt
Matches statements.
llvm::DenseSet< SymbolRef > InvalidatedSymbols
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
bool Call(InterpState &S, CodePtr OpPC, const Function *Func, uint32_t VarArgSize)
bool Init(InterpState &S, CodePtr OpPC)
The JSON file list parser is used to communicate input to InstallAPI.
const FunctionProtoType * T
@ Class
The "class" keyword introduces the elaborated-type-specifier.
Diagnostic wrappers for TextAPI types for error reporting.
static raw_ostream & operator<<(raw_ostream &Out, BindingKey K)
__UINTPTR_TYPE__ uintptr_t
An unsigned integer type with the property that any valid pointer to void can be converted to this ty...