10b57cec5SDimitry Andric //= ProgramState.cpp - Path-Sensitive "State" for tracking values --*- C++ -*--=
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements ProgramState and ProgramStateManager.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
140b57cec5SDimitry Andric #include "clang/Analysis/CFG.h"
150b57cec5SDimitry Andric #include "clang/Basic/JsonSupport.h"
160b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
170b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
18a7dea167SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"
195ffd83dbSDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
200b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
210b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
22bdd1243dSDimitry Andric #include <optional>
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric using namespace clang;
250b57cec5SDimitry Andric using namespace ento;
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric namespace clang { namespace ento {
280b57cec5SDimitry Andric /// Increments the number of times this state is referenced.
290b57cec5SDimitry Andric
ProgramStateRetain(const ProgramState * state)300b57cec5SDimitry Andric void ProgramStateRetain(const ProgramState *state) {
310b57cec5SDimitry Andric ++const_cast<ProgramState*>(state)->refCount;
320b57cec5SDimitry Andric }
330b57cec5SDimitry Andric
340b57cec5SDimitry Andric /// Decrement the number of times this state is referenced.
ProgramStateRelease(const ProgramState * state)350b57cec5SDimitry Andric void ProgramStateRelease(const ProgramState *state) {
360b57cec5SDimitry Andric assert(state->refCount > 0);
370b57cec5SDimitry Andric ProgramState *s = const_cast<ProgramState*>(state);
380b57cec5SDimitry Andric if (--s->refCount == 0) {
390b57cec5SDimitry Andric ProgramStateManager &Mgr = s->getStateManager();
400b57cec5SDimitry Andric Mgr.StateSet.RemoveNode(s);
410b57cec5SDimitry Andric s->~ProgramState();
420b57cec5SDimitry Andric Mgr.freeStates.push_back(s);
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric }}
460b57cec5SDimitry Andric
ProgramState(ProgramStateManager * mgr,const Environment & env,StoreRef st,GenericDataMap gdm)470b57cec5SDimitry Andric ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env,
480b57cec5SDimitry Andric StoreRef st, GenericDataMap gdm)
490b57cec5SDimitry Andric : stateMgr(mgr),
500b57cec5SDimitry Andric Env(env),
510b57cec5SDimitry Andric store(st.getStore()),
520b57cec5SDimitry Andric GDM(gdm),
530b57cec5SDimitry Andric refCount(0) {
540b57cec5SDimitry Andric stateMgr->getStoreManager().incrementReferenceCount(store);
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric
ProgramState(const ProgramState & RHS)570b57cec5SDimitry Andric ProgramState::ProgramState(const ProgramState &RHS)
5804eeddc0SDimitry Andric : stateMgr(RHS.stateMgr), Env(RHS.Env), store(RHS.store), GDM(RHS.GDM),
5981ad6265SDimitry Andric PosteriorlyOverconstrained(RHS.PosteriorlyOverconstrained), refCount(0) {
600b57cec5SDimitry Andric stateMgr->getStoreManager().incrementReferenceCount(store);
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric
~ProgramState()630b57cec5SDimitry Andric ProgramState::~ProgramState() {
640b57cec5SDimitry Andric if (store)
650b57cec5SDimitry Andric stateMgr->getStoreManager().decrementReferenceCount(store);
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric
getID() const680b57cec5SDimitry Andric int64_t ProgramState::getID() const {
690b57cec5SDimitry Andric return getStateManager().Alloc.identifyKnownAlignedObject<ProgramState>(this);
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric
ProgramStateManager(ASTContext & Ctx,StoreManagerCreator CreateSMgr,ConstraintManagerCreator CreateCMgr,llvm::BumpPtrAllocator & alloc,ExprEngine * ExprEng)720b57cec5SDimitry Andric ProgramStateManager::ProgramStateManager(ASTContext &Ctx,
730b57cec5SDimitry Andric StoreManagerCreator CreateSMgr,
740b57cec5SDimitry Andric ConstraintManagerCreator CreateCMgr,
750b57cec5SDimitry Andric llvm::BumpPtrAllocator &alloc,
765ffd83dbSDimitry Andric ExprEngine *ExprEng)
775ffd83dbSDimitry Andric : Eng(ExprEng), EnvMgr(alloc), GDMFactory(alloc),
780b57cec5SDimitry Andric svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),
790b57cec5SDimitry Andric CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) {
800b57cec5SDimitry Andric StoreMgr = (*CreateSMgr)(*this);
815ffd83dbSDimitry Andric ConstraintMgr = (*CreateCMgr)(*this, ExprEng);
820b57cec5SDimitry Andric }
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric
~ProgramStateManager()850b57cec5SDimitry Andric ProgramStateManager::~ProgramStateManager() {
860b57cec5SDimitry Andric for (GDMContextsTy::iterator I=GDMContexts.begin(), E=GDMContexts.end();
870b57cec5SDimitry Andric I!=E; ++I)
880b57cec5SDimitry Andric I->second.second(I->second.first);
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric
removeDeadBindingsFromEnvironmentAndStore(ProgramStateRef state,const StackFrameContext * LCtx,SymbolReaper & SymReaper)91480093f4SDimitry Andric ProgramStateRef ProgramStateManager::removeDeadBindingsFromEnvironmentAndStore(
92480093f4SDimitry Andric ProgramStateRef state, const StackFrameContext *LCtx,
930b57cec5SDimitry Andric SymbolReaper &SymReaper) {
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric // This code essentially performs a "mark-and-sweep" of the VariableBindings.
960b57cec5SDimitry Andric // The roots are any Block-level exprs and Decls that our liveness algorithm
970b57cec5SDimitry Andric // tells us are live. We then see what Decls they may reference, and keep
980b57cec5SDimitry Andric // those around. This code more than likely can be made faster, and the
990b57cec5SDimitry Andric // frequency of which this method is called should be experimented with
1000b57cec5SDimitry Andric // for optimum performance.
1010b57cec5SDimitry Andric ProgramState NewState = *state;
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric NewState.Env = EnvMgr.removeDeadBindings(NewState.Env, SymReaper, state);
1040b57cec5SDimitry Andric
1050b57cec5SDimitry Andric // Clean up the store.
1060b57cec5SDimitry Andric StoreRef newStore = StoreMgr->removeDeadBindings(NewState.getStore(), LCtx,
1070b57cec5SDimitry Andric SymReaper);
1080b57cec5SDimitry Andric NewState.setStore(newStore);
1090b57cec5SDimitry Andric SymReaper.setReapedStore(newStore);
1100b57cec5SDimitry Andric
111480093f4SDimitry Andric return getPersistentState(NewState);
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric
bindLoc(Loc LV,SVal V,const LocationContext * LCtx,bool notifyChanges) const1140b57cec5SDimitry Andric ProgramStateRef ProgramState::bindLoc(Loc LV,
1150b57cec5SDimitry Andric SVal V,
1160b57cec5SDimitry Andric const LocationContext *LCtx,
1170b57cec5SDimitry Andric bool notifyChanges) const {
1180b57cec5SDimitry Andric ProgramStateManager &Mgr = getStateManager();
1190b57cec5SDimitry Andric ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(),
1200b57cec5SDimitry Andric LV, V));
1210b57cec5SDimitry Andric const MemRegion *MR = LV.getAsRegion();
1220b57cec5SDimitry Andric if (MR && notifyChanges)
1230b57cec5SDimitry Andric return Mgr.getOwningEngine().processRegionChange(newState, MR, LCtx);
1240b57cec5SDimitry Andric
1250b57cec5SDimitry Andric return newState;
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric ProgramStateRef
bindDefaultInitial(SVal loc,SVal V,const LocationContext * LCtx) const1290b57cec5SDimitry Andric ProgramState::bindDefaultInitial(SVal loc, SVal V,
1300b57cec5SDimitry Andric const LocationContext *LCtx) const {
1310b57cec5SDimitry Andric ProgramStateManager &Mgr = getStateManager();
1320b57cec5SDimitry Andric const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();
1330b57cec5SDimitry Andric const StoreRef &newStore = Mgr.StoreMgr->BindDefaultInitial(getStore(), R, V);
1340b57cec5SDimitry Andric ProgramStateRef new_state = makeWithStore(newStore);
1350b57cec5SDimitry Andric return Mgr.getOwningEngine().processRegionChange(new_state, R, LCtx);
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric ProgramStateRef
bindDefaultZero(SVal loc,const LocationContext * LCtx) const1390b57cec5SDimitry Andric ProgramState::bindDefaultZero(SVal loc, const LocationContext *LCtx) const {
1400b57cec5SDimitry Andric ProgramStateManager &Mgr = getStateManager();
1410b57cec5SDimitry Andric const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();
1420b57cec5SDimitry Andric const StoreRef &newStore = Mgr.StoreMgr->BindDefaultZero(getStore(), R);
1430b57cec5SDimitry Andric ProgramStateRef new_state = makeWithStore(newStore);
1440b57cec5SDimitry Andric return Mgr.getOwningEngine().processRegionChange(new_state, R, LCtx);
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric
1470b57cec5SDimitry Andric typedef ArrayRef<const MemRegion *> RegionList;
1480b57cec5SDimitry Andric typedef ArrayRef<SVal> ValueList;
1490b57cec5SDimitry Andric
1500b57cec5SDimitry Andric ProgramStateRef
invalidateRegions(RegionList Regions,const Expr * E,unsigned Count,const LocationContext * LCtx,bool CausedByPointerEscape,InvalidatedSymbols * IS,const CallEvent * Call,RegionAndSymbolInvalidationTraits * ITraits) const1510b57cec5SDimitry Andric ProgramState::invalidateRegions(RegionList Regions,
1520b57cec5SDimitry Andric const Expr *E, unsigned Count,
1530b57cec5SDimitry Andric const LocationContext *LCtx,
1540b57cec5SDimitry Andric bool CausedByPointerEscape,
1550b57cec5SDimitry Andric InvalidatedSymbols *IS,
1560b57cec5SDimitry Andric const CallEvent *Call,
1570b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits *ITraits) const {
1580b57cec5SDimitry Andric SmallVector<SVal, 8> Values;
159*fe013be4SDimitry Andric for (const MemRegion *Reg : Regions)
160*fe013be4SDimitry Andric Values.push_back(loc::MemRegionVal(Reg));
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
1630b57cec5SDimitry Andric IS, ITraits, Call);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
1660b57cec5SDimitry Andric ProgramStateRef
invalidateRegions(ValueList Values,const Expr * E,unsigned Count,const LocationContext * LCtx,bool CausedByPointerEscape,InvalidatedSymbols * IS,const CallEvent * Call,RegionAndSymbolInvalidationTraits * ITraits) const1670b57cec5SDimitry Andric ProgramState::invalidateRegions(ValueList Values,
1680b57cec5SDimitry Andric const Expr *E, unsigned Count,
1690b57cec5SDimitry Andric const LocationContext *LCtx,
1700b57cec5SDimitry Andric bool CausedByPointerEscape,
1710b57cec5SDimitry Andric InvalidatedSymbols *IS,
1720b57cec5SDimitry Andric const CallEvent *Call,
1730b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits *ITraits) const {
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric return invalidateRegionsImpl(Values, E, Count, LCtx, CausedByPointerEscape,
1760b57cec5SDimitry Andric IS, ITraits, Call);
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric
1790b57cec5SDimitry Andric ProgramStateRef
invalidateRegionsImpl(ValueList Values,const Expr * E,unsigned Count,const LocationContext * LCtx,bool CausedByPointerEscape,InvalidatedSymbols * IS,RegionAndSymbolInvalidationTraits * ITraits,const CallEvent * Call) const1800b57cec5SDimitry Andric ProgramState::invalidateRegionsImpl(ValueList Values,
1810b57cec5SDimitry Andric const Expr *E, unsigned Count,
1820b57cec5SDimitry Andric const LocationContext *LCtx,
1830b57cec5SDimitry Andric bool CausedByPointerEscape,
1840b57cec5SDimitry Andric InvalidatedSymbols *IS,
1850b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits *ITraits,
1860b57cec5SDimitry Andric const CallEvent *Call) const {
1870b57cec5SDimitry Andric ProgramStateManager &Mgr = getStateManager();
1885ffd83dbSDimitry Andric ExprEngine &Eng = Mgr.getOwningEngine();
1890b57cec5SDimitry Andric
1900b57cec5SDimitry Andric InvalidatedSymbols InvalidatedSyms;
1910b57cec5SDimitry Andric if (!IS)
1920b57cec5SDimitry Andric IS = &InvalidatedSyms;
1930b57cec5SDimitry Andric
1940b57cec5SDimitry Andric RegionAndSymbolInvalidationTraits ITraitsLocal;
1950b57cec5SDimitry Andric if (!ITraits)
1960b57cec5SDimitry Andric ITraits = &ITraitsLocal;
1970b57cec5SDimitry Andric
1980b57cec5SDimitry Andric StoreManager::InvalidatedRegions TopLevelInvalidated;
1990b57cec5SDimitry Andric StoreManager::InvalidatedRegions Invalidated;
2000b57cec5SDimitry Andric const StoreRef &newStore
2010b57cec5SDimitry Andric = Mgr.StoreMgr->invalidateRegions(getStore(), Values, E, Count, LCtx, Call,
2020b57cec5SDimitry Andric *IS, *ITraits, &TopLevelInvalidated,
2030b57cec5SDimitry Andric &Invalidated);
2040b57cec5SDimitry Andric
2050b57cec5SDimitry Andric ProgramStateRef newState = makeWithStore(newStore);
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andric if (CausedByPointerEscape) {
2080b57cec5SDimitry Andric newState = Eng.notifyCheckersOfPointerEscape(newState, IS,
2090b57cec5SDimitry Andric TopLevelInvalidated,
2100b57cec5SDimitry Andric Call,
2110b57cec5SDimitry Andric *ITraits);
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric return Eng.processRegionChanges(newState, IS, TopLevelInvalidated,
2150b57cec5SDimitry Andric Invalidated, LCtx, Call);
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric
killBinding(Loc LV) const2180b57cec5SDimitry Andric ProgramStateRef ProgramState::killBinding(Loc LV) const {
2190b57cec5SDimitry Andric Store OldStore = getStore();
2200b57cec5SDimitry Andric const StoreRef &newStore =
2210b57cec5SDimitry Andric getStateManager().StoreMgr->killBinding(OldStore, LV);
2220b57cec5SDimitry Andric
2230b57cec5SDimitry Andric if (newStore.getStore() == OldStore)
2240b57cec5SDimitry Andric return this;
2250b57cec5SDimitry Andric
2260b57cec5SDimitry Andric return makeWithStore(newStore);
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric ProgramStateRef
enterStackFrame(const CallEvent & Call,const StackFrameContext * CalleeCtx) const2300b57cec5SDimitry Andric ProgramState::enterStackFrame(const CallEvent &Call,
2310b57cec5SDimitry Andric const StackFrameContext *CalleeCtx) const {
2320b57cec5SDimitry Andric const StoreRef &NewStore =
2330b57cec5SDimitry Andric getStateManager().StoreMgr->enterStackFrame(getStore(), Call, CalleeCtx);
2340b57cec5SDimitry Andric return makeWithStore(NewStore);
2350b57cec5SDimitry Andric }
2360b57cec5SDimitry Andric
getSelfSVal(const LocationContext * LCtx) const2375ffd83dbSDimitry Andric SVal ProgramState::getSelfSVal(const LocationContext *LCtx) const {
2385ffd83dbSDimitry Andric const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();
2395ffd83dbSDimitry Andric if (!SelfDecl)
2405ffd83dbSDimitry Andric return SVal();
2415ffd83dbSDimitry Andric return getSVal(getRegion(SelfDecl, LCtx));
2425ffd83dbSDimitry Andric }
2435ffd83dbSDimitry Andric
getSValAsScalarOrLoc(const MemRegion * R) const2440b57cec5SDimitry Andric SVal ProgramState::getSValAsScalarOrLoc(const MemRegion *R) const {
2450b57cec5SDimitry Andric // We only want to do fetches from regions that we can actually bind
2460b57cec5SDimitry Andric // values. For example, SymbolicRegions of type 'id<...>' cannot
2470b57cec5SDimitry Andric // have direct bindings (but their can be bindings on their subregions).
2480b57cec5SDimitry Andric if (!R->isBoundable())
2490b57cec5SDimitry Andric return UnknownVal();
2500b57cec5SDimitry Andric
2510b57cec5SDimitry Andric if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {
2520b57cec5SDimitry Andric QualType T = TR->getValueType();
2530b57cec5SDimitry Andric if (Loc::isLocType(T) || T->isIntegralOrEnumerationType())
2540b57cec5SDimitry Andric return getSVal(R);
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric
2570b57cec5SDimitry Andric return UnknownVal();
2580b57cec5SDimitry Andric }
2590b57cec5SDimitry Andric
getSVal(Loc location,QualType T) const2600b57cec5SDimitry Andric SVal ProgramState::getSVal(Loc location, QualType T) const {
2610b57cec5SDimitry Andric SVal V = getRawSVal(location, T);
2620b57cec5SDimitry Andric
2630b57cec5SDimitry Andric // If 'V' is a symbolic value that is *perfectly* constrained to
2640b57cec5SDimitry Andric // be a constant value, use that value instead to lessen the burden
2650b57cec5SDimitry Andric // on later analysis stages (so we have less symbolic values to reason
2660b57cec5SDimitry Andric // about).
2670b57cec5SDimitry Andric // We only go into this branch if we can convert the APSInt value we have
2680b57cec5SDimitry Andric // to the type of T, which is not always the case (e.g. for void).
2690b57cec5SDimitry Andric if (!T.isNull() && (T->isIntegralOrEnumerationType() || Loc::isLocType(T))) {
2700b57cec5SDimitry Andric if (SymbolRef sym = V.getAsSymbol()) {
2710b57cec5SDimitry Andric if (const llvm::APSInt *Int = getStateManager()
2720b57cec5SDimitry Andric .getConstraintManager()
2730b57cec5SDimitry Andric .getSymVal(this, sym)) {
2740b57cec5SDimitry Andric // FIXME: Because we don't correctly model (yet) sign-extension
2750b57cec5SDimitry Andric // and truncation of symbolic values, we need to convert
2760b57cec5SDimitry Andric // the integer value to the correct signedness and bitwidth.
2770b57cec5SDimitry Andric //
2780b57cec5SDimitry Andric // This shows up in the following:
2790b57cec5SDimitry Andric //
2800b57cec5SDimitry Andric // char foo();
2810b57cec5SDimitry Andric // unsigned x = foo();
2820b57cec5SDimitry Andric // if (x == 54)
2830b57cec5SDimitry Andric // ...
2840b57cec5SDimitry Andric //
2850b57cec5SDimitry Andric // The symbolic value stored to 'x' is actually the conjured
2860b57cec5SDimitry Andric // symbol for the call to foo(); the type of that symbol is 'char',
2870b57cec5SDimitry Andric // not unsigned.
2880b57cec5SDimitry Andric const llvm::APSInt &NewV = getBasicVals().Convert(T, *Int);
2890b57cec5SDimitry Andric
2900b57cec5SDimitry Andric if (V.getAs<Loc>())
2910b57cec5SDimitry Andric return loc::ConcreteInt(NewV);
2920b57cec5SDimitry Andric else
2930b57cec5SDimitry Andric return nonloc::ConcreteInt(NewV);
2940b57cec5SDimitry Andric }
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric
2980b57cec5SDimitry Andric return V;
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric
BindExpr(const Stmt * S,const LocationContext * LCtx,SVal V,bool Invalidate) const3010b57cec5SDimitry Andric ProgramStateRef ProgramState::BindExpr(const Stmt *S,
3020b57cec5SDimitry Andric const LocationContext *LCtx,
3030b57cec5SDimitry Andric SVal V, bool Invalidate) const{
3040b57cec5SDimitry Andric Environment NewEnv =
3050b57cec5SDimitry Andric getStateManager().EnvMgr.bindExpr(Env, EnvironmentEntry(S, LCtx), V,
3060b57cec5SDimitry Andric Invalidate);
3070b57cec5SDimitry Andric if (NewEnv == Env)
3080b57cec5SDimitry Andric return this;
3090b57cec5SDimitry Andric
3100b57cec5SDimitry Andric ProgramState NewSt = *this;
3110b57cec5SDimitry Andric NewSt.Env = NewEnv;
3120b57cec5SDimitry Andric return getStateManager().getPersistentState(NewSt);
3130b57cec5SDimitry Andric }
3140b57cec5SDimitry Andric
315bdd1243dSDimitry Andric [[nodiscard]] std::pair<ProgramStateRef, ProgramStateRef>
assumeInBoundDual(DefinedOrUnknownSVal Idx,DefinedOrUnknownSVal UpperBound,QualType indexTy) const31681ad6265SDimitry Andric ProgramState::assumeInBoundDual(DefinedOrUnknownSVal Idx,
3170b57cec5SDimitry Andric DefinedOrUnknownSVal UpperBound,
3180b57cec5SDimitry Andric QualType indexTy) const {
3190b57cec5SDimitry Andric if (Idx.isUnknown() || UpperBound.isUnknown())
32081ad6265SDimitry Andric return {this, this};
3210b57cec5SDimitry Andric
3220b57cec5SDimitry Andric // Build an expression for 0 <= Idx < UpperBound.
3230b57cec5SDimitry Andric // This is the same as Idx + MIN < UpperBound + MIN, if overflow is allowed.
3240b57cec5SDimitry Andric // FIXME: This should probably be part of SValBuilder.
3250b57cec5SDimitry Andric ProgramStateManager &SM = getStateManager();
3260b57cec5SDimitry Andric SValBuilder &svalBuilder = SM.getSValBuilder();
3270b57cec5SDimitry Andric ASTContext &Ctx = svalBuilder.getContext();
3280b57cec5SDimitry Andric
3290b57cec5SDimitry Andric // Get the offset: the minimum value of the array index type.
3300b57cec5SDimitry Andric BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();
3310b57cec5SDimitry Andric if (indexTy.isNull())
3320b57cec5SDimitry Andric indexTy = svalBuilder.getArrayIndexType();
3330b57cec5SDimitry Andric nonloc::ConcreteInt Min(BVF.getMinValue(indexTy));
3340b57cec5SDimitry Andric
3350b57cec5SDimitry Andric // Adjust the index.
3360b57cec5SDimitry Andric SVal newIdx = svalBuilder.evalBinOpNN(this, BO_Add,
3370b57cec5SDimitry Andric Idx.castAs<NonLoc>(), Min, indexTy);
3380b57cec5SDimitry Andric if (newIdx.isUnknownOrUndef())
33981ad6265SDimitry Andric return {this, this};
3400b57cec5SDimitry Andric
3410b57cec5SDimitry Andric // Adjust the upper bound.
3420b57cec5SDimitry Andric SVal newBound =
3430b57cec5SDimitry Andric svalBuilder.evalBinOpNN(this, BO_Add, UpperBound.castAs<NonLoc>(),
3440b57cec5SDimitry Andric Min, indexTy);
3450b57cec5SDimitry Andric
3460b57cec5SDimitry Andric if (newBound.isUnknownOrUndef())
34781ad6265SDimitry Andric return {this, this};
3480b57cec5SDimitry Andric
3490b57cec5SDimitry Andric // Build the actual comparison.
3500b57cec5SDimitry Andric SVal inBound = svalBuilder.evalBinOpNN(this, BO_LT, newIdx.castAs<NonLoc>(),
3510b57cec5SDimitry Andric newBound.castAs<NonLoc>(), Ctx.IntTy);
3520b57cec5SDimitry Andric if (inBound.isUnknownOrUndef())
35381ad6265SDimitry Andric return {this, this};
3540b57cec5SDimitry Andric
3550b57cec5SDimitry Andric // Finally, let the constraint manager take care of it.
3560b57cec5SDimitry Andric ConstraintManager &CM = SM.getConstraintManager();
35781ad6265SDimitry Andric return CM.assumeDual(this, inBound.castAs<DefinedSVal>());
35881ad6265SDimitry Andric }
35981ad6265SDimitry Andric
assumeInBound(DefinedOrUnknownSVal Idx,DefinedOrUnknownSVal UpperBound,bool Assumption,QualType indexTy) const36081ad6265SDimitry Andric ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,
36181ad6265SDimitry Andric DefinedOrUnknownSVal UpperBound,
36281ad6265SDimitry Andric bool Assumption,
36381ad6265SDimitry Andric QualType indexTy) const {
36481ad6265SDimitry Andric std::pair<ProgramStateRef, ProgramStateRef> R =
36581ad6265SDimitry Andric assumeInBoundDual(Idx, UpperBound, indexTy);
36681ad6265SDimitry Andric return Assumption ? R.first : R.second;
3670b57cec5SDimitry Andric }
3680b57cec5SDimitry Andric
isNonNull(SVal V) const3690b57cec5SDimitry Andric ConditionTruthVal ProgramState::isNonNull(SVal V) const {
3700b57cec5SDimitry Andric ConditionTruthVal IsNull = isNull(V);
3710b57cec5SDimitry Andric if (IsNull.isUnderconstrained())
3720b57cec5SDimitry Andric return IsNull;
3730b57cec5SDimitry Andric return ConditionTruthVal(!IsNull.getValue());
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric
areEqual(SVal Lhs,SVal Rhs) const3760b57cec5SDimitry Andric ConditionTruthVal ProgramState::areEqual(SVal Lhs, SVal Rhs) const {
3770b57cec5SDimitry Andric return stateMgr->getSValBuilder().areEqual(this, Lhs, Rhs);
3780b57cec5SDimitry Andric }
3790b57cec5SDimitry Andric
isNull(SVal V) const3800b57cec5SDimitry Andric ConditionTruthVal ProgramState::isNull(SVal V) const {
3810b57cec5SDimitry Andric if (V.isZeroConstant())
3820b57cec5SDimitry Andric return true;
3830b57cec5SDimitry Andric
3840b57cec5SDimitry Andric if (V.isConstant())
3850b57cec5SDimitry Andric return false;
3860b57cec5SDimitry Andric
3870b57cec5SDimitry Andric SymbolRef Sym = V.getAsSymbol(/* IncludeBaseRegion */ true);
3880b57cec5SDimitry Andric if (!Sym)
3890b57cec5SDimitry Andric return ConditionTruthVal();
3900b57cec5SDimitry Andric
3910b57cec5SDimitry Andric return getStateManager().ConstraintMgr->isNull(this, Sym);
3920b57cec5SDimitry Andric }
3930b57cec5SDimitry Andric
getInitialState(const LocationContext * InitLoc)3940b57cec5SDimitry Andric ProgramStateRef ProgramStateManager::getInitialState(const LocationContext *InitLoc) {
3950b57cec5SDimitry Andric ProgramState State(this,
3960b57cec5SDimitry Andric EnvMgr.getInitialEnvironment(),
3970b57cec5SDimitry Andric StoreMgr->getInitialStore(InitLoc),
3980b57cec5SDimitry Andric GDMFactory.getEmptyMap());
3990b57cec5SDimitry Andric
4000b57cec5SDimitry Andric return getPersistentState(State);
4010b57cec5SDimitry Andric }
4020b57cec5SDimitry Andric
getPersistentStateWithGDM(ProgramStateRef FromState,ProgramStateRef GDMState)4030b57cec5SDimitry Andric ProgramStateRef ProgramStateManager::getPersistentStateWithGDM(
4040b57cec5SDimitry Andric ProgramStateRef FromState,
4050b57cec5SDimitry Andric ProgramStateRef GDMState) {
4060b57cec5SDimitry Andric ProgramState NewState(*FromState);
4070b57cec5SDimitry Andric NewState.GDM = GDMState->GDM;
4080b57cec5SDimitry Andric return getPersistentState(NewState);
4090b57cec5SDimitry Andric }
4100b57cec5SDimitry Andric
getPersistentState(ProgramState & State)4110b57cec5SDimitry Andric ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) {
4120b57cec5SDimitry Andric
4130b57cec5SDimitry Andric llvm::FoldingSetNodeID ID;
4140b57cec5SDimitry Andric State.Profile(ID);
4150b57cec5SDimitry Andric void *InsertPos;
4160b57cec5SDimitry Andric
4170b57cec5SDimitry Andric if (ProgramState *I = StateSet.FindNodeOrInsertPos(ID, InsertPos))
4180b57cec5SDimitry Andric return I;
4190b57cec5SDimitry Andric
4200b57cec5SDimitry Andric ProgramState *newState = nullptr;
4210b57cec5SDimitry Andric if (!freeStates.empty()) {
4220b57cec5SDimitry Andric newState = freeStates.back();
4230b57cec5SDimitry Andric freeStates.pop_back();
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric else {
426*fe013be4SDimitry Andric newState = Alloc.Allocate<ProgramState>();
4270b57cec5SDimitry Andric }
4280b57cec5SDimitry Andric new (newState) ProgramState(State);
4290b57cec5SDimitry Andric StateSet.InsertNode(newState, InsertPos);
4300b57cec5SDimitry Andric return newState;
4310b57cec5SDimitry Andric }
4320b57cec5SDimitry Andric
makeWithStore(const StoreRef & store) const4330b57cec5SDimitry Andric ProgramStateRef ProgramState::makeWithStore(const StoreRef &store) const {
4340b57cec5SDimitry Andric ProgramState NewSt(*this);
4350b57cec5SDimitry Andric NewSt.setStore(store);
4360b57cec5SDimitry Andric return getStateManager().getPersistentState(NewSt);
4370b57cec5SDimitry Andric }
4380b57cec5SDimitry Andric
cloneAsPosteriorlyOverconstrained() const43981ad6265SDimitry Andric ProgramStateRef ProgramState::cloneAsPosteriorlyOverconstrained() const {
44081ad6265SDimitry Andric ProgramState NewSt(*this);
44181ad6265SDimitry Andric NewSt.PosteriorlyOverconstrained = true;
44281ad6265SDimitry Andric return getStateManager().getPersistentState(NewSt);
44381ad6265SDimitry Andric }
44481ad6265SDimitry Andric
setStore(const StoreRef & newStore)4450b57cec5SDimitry Andric void ProgramState::setStore(const StoreRef &newStore) {
4460b57cec5SDimitry Andric Store newStoreStore = newStore.getStore();
4470b57cec5SDimitry Andric if (newStoreStore)
4480b57cec5SDimitry Andric stateMgr->getStoreManager().incrementReferenceCount(newStoreStore);
4490b57cec5SDimitry Andric if (store)
4500b57cec5SDimitry Andric stateMgr->getStoreManager().decrementReferenceCount(store);
4510b57cec5SDimitry Andric store = newStoreStore;
4520b57cec5SDimitry Andric }
4530b57cec5SDimitry Andric
4540b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4550b57cec5SDimitry Andric // State pretty-printing.
4560b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4570b57cec5SDimitry Andric
printJson(raw_ostream & Out,const LocationContext * LCtx,const char * NL,unsigned int Space,bool IsDot) const4580b57cec5SDimitry Andric void ProgramState::printJson(raw_ostream &Out, const LocationContext *LCtx,
4590b57cec5SDimitry Andric const char *NL, unsigned int Space,
4600b57cec5SDimitry Andric bool IsDot) const {
4610b57cec5SDimitry Andric Indent(Out, Space, IsDot) << "\"program_state\": {" << NL;
4620b57cec5SDimitry Andric ++Space;
4630b57cec5SDimitry Andric
4640b57cec5SDimitry Andric ProgramStateManager &Mgr = getStateManager();
4650b57cec5SDimitry Andric
4660b57cec5SDimitry Andric // Print the store.
4670b57cec5SDimitry Andric Mgr.getStoreManager().printJson(Out, getStore(), NL, Space, IsDot);
4680b57cec5SDimitry Andric
4690b57cec5SDimitry Andric // Print out the environment.
4700b57cec5SDimitry Andric Env.printJson(Out, Mgr.getContext(), LCtx, NL, Space, IsDot);
4710b57cec5SDimitry Andric
4720b57cec5SDimitry Andric // Print out the constraints.
4730b57cec5SDimitry Andric Mgr.getConstraintManager().printJson(Out, this, NL, Space, IsDot);
4740b57cec5SDimitry Andric
4750b57cec5SDimitry Andric // Print out the tracked dynamic types.
4760b57cec5SDimitry Andric printDynamicTypeInfoJson(Out, this, NL, Space, IsDot);
4770b57cec5SDimitry Andric
4780b57cec5SDimitry Andric // Print checker-specific data.
4790b57cec5SDimitry Andric Mgr.getOwningEngine().printJson(Out, this, LCtx, NL, Space, IsDot);
4800b57cec5SDimitry Andric
4810b57cec5SDimitry Andric --Space;
4820b57cec5SDimitry Andric Indent(Out, Space, IsDot) << '}';
4830b57cec5SDimitry Andric }
4840b57cec5SDimitry Andric
printDOT(raw_ostream & Out,const LocationContext * LCtx,unsigned int Space) const4850b57cec5SDimitry Andric void ProgramState::printDOT(raw_ostream &Out, const LocationContext *LCtx,
4860b57cec5SDimitry Andric unsigned int Space) const {
4870b57cec5SDimitry Andric printJson(Out, LCtx, /*NL=*/"\\l", Space, /*IsDot=*/true);
4880b57cec5SDimitry Andric }
4890b57cec5SDimitry Andric
dump() const4900b57cec5SDimitry Andric LLVM_DUMP_METHOD void ProgramState::dump() const {
4910b57cec5SDimitry Andric printJson(llvm::errs());
4920b57cec5SDimitry Andric }
4930b57cec5SDimitry Andric
getAnalysisManager() const4940b57cec5SDimitry Andric AnalysisManager& ProgramState::getAnalysisManager() const {
4950b57cec5SDimitry Andric return stateMgr->getOwningEngine().getAnalysisManager();
4960b57cec5SDimitry Andric }
4970b57cec5SDimitry Andric
4980b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
4990b57cec5SDimitry Andric // Generic Data Map.
5000b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
5010b57cec5SDimitry Andric
FindGDM(void * K) const5020b57cec5SDimitry Andric void *const* ProgramState::FindGDM(void *K) const {
5030b57cec5SDimitry Andric return GDM.lookup(K);
5040b57cec5SDimitry Andric }
5050b57cec5SDimitry Andric
5060b57cec5SDimitry Andric void*
FindGDMContext(void * K,void * (* CreateContext)(llvm::BumpPtrAllocator &),void (* DeleteContext)(void *))5070b57cec5SDimitry Andric ProgramStateManager::FindGDMContext(void *K,
5080b57cec5SDimitry Andric void *(*CreateContext)(llvm::BumpPtrAllocator&),
5090b57cec5SDimitry Andric void (*DeleteContext)(void*)) {
5100b57cec5SDimitry Andric
5110b57cec5SDimitry Andric std::pair<void*, void (*)(void*)>& p = GDMContexts[K];
5120b57cec5SDimitry Andric if (!p.first) {
5130b57cec5SDimitry Andric p.first = CreateContext(Alloc);
5140b57cec5SDimitry Andric p.second = DeleteContext;
5150b57cec5SDimitry Andric }
5160b57cec5SDimitry Andric
5170b57cec5SDimitry Andric return p.first;
5180b57cec5SDimitry Andric }
5190b57cec5SDimitry Andric
addGDM(ProgramStateRef St,void * Key,void * Data)5200b57cec5SDimitry Andric ProgramStateRef ProgramStateManager::addGDM(ProgramStateRef St, void *Key, void *Data){
5210b57cec5SDimitry Andric ProgramState::GenericDataMap M1 = St->getGDM();
5220b57cec5SDimitry Andric ProgramState::GenericDataMap M2 = GDMFactory.add(M1, Key, Data);
5230b57cec5SDimitry Andric
5240b57cec5SDimitry Andric if (M1 == M2)
5250b57cec5SDimitry Andric return St;
5260b57cec5SDimitry Andric
5270b57cec5SDimitry Andric ProgramState NewSt = *St;
5280b57cec5SDimitry Andric NewSt.GDM = M2;
5290b57cec5SDimitry Andric return getPersistentState(NewSt);
5300b57cec5SDimitry Andric }
5310b57cec5SDimitry Andric
removeGDM(ProgramStateRef state,void * Key)5320b57cec5SDimitry Andric ProgramStateRef ProgramStateManager::removeGDM(ProgramStateRef state, void *Key) {
5330b57cec5SDimitry Andric ProgramState::GenericDataMap OldM = state->getGDM();
5340b57cec5SDimitry Andric ProgramState::GenericDataMap NewM = GDMFactory.remove(OldM, Key);
5350b57cec5SDimitry Andric
5360b57cec5SDimitry Andric if (NewM == OldM)
5370b57cec5SDimitry Andric return state;
5380b57cec5SDimitry Andric
5390b57cec5SDimitry Andric ProgramState NewState = *state;
5400b57cec5SDimitry Andric NewState.GDM = NewM;
5410b57cec5SDimitry Andric return getPersistentState(NewState);
5420b57cec5SDimitry Andric }
5430b57cec5SDimitry Andric
scan(nonloc::LazyCompoundVal val)5440b57cec5SDimitry Andric bool ScanReachableSymbols::scan(nonloc::LazyCompoundVal val) {
5450b57cec5SDimitry Andric bool wasVisited = !visited.insert(val.getCVData()).second;
5460b57cec5SDimitry Andric if (wasVisited)
5470b57cec5SDimitry Andric return true;
5480b57cec5SDimitry Andric
5490b57cec5SDimitry Andric StoreManager &StoreMgr = state->getStateManager().getStoreManager();
5500b57cec5SDimitry Andric // FIXME: We don't really want to use getBaseRegion() here because pointer
5510b57cec5SDimitry Andric // arithmetic doesn't apply, but scanReachableSymbols only accepts base
5520b57cec5SDimitry Andric // regions right now.
5530b57cec5SDimitry Andric const MemRegion *R = val.getRegion()->getBaseRegion();
5540b57cec5SDimitry Andric return StoreMgr.scanReachableSymbols(val.getStore(), R, *this);
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric
scan(nonloc::CompoundVal val)5570b57cec5SDimitry Andric bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {
558*fe013be4SDimitry Andric for (SVal V : val)
559*fe013be4SDimitry Andric if (!scan(V))
5600b57cec5SDimitry Andric return false;
5610b57cec5SDimitry Andric
5620b57cec5SDimitry Andric return true;
5630b57cec5SDimitry Andric }
5640b57cec5SDimitry Andric
scan(const SymExpr * sym)5650b57cec5SDimitry Andric bool ScanReachableSymbols::scan(const SymExpr *sym) {
566*fe013be4SDimitry Andric for (SymbolRef SubSym : sym->symbols()) {
567*fe013be4SDimitry Andric bool wasVisited = !visited.insert(SubSym).second;
5680b57cec5SDimitry Andric if (wasVisited)
5690b57cec5SDimitry Andric continue;
5700b57cec5SDimitry Andric
571*fe013be4SDimitry Andric if (!visitor.VisitSymbol(SubSym))
5720b57cec5SDimitry Andric return false;
5730b57cec5SDimitry Andric }
5740b57cec5SDimitry Andric
5750b57cec5SDimitry Andric return true;
5760b57cec5SDimitry Andric }
5770b57cec5SDimitry Andric
scan(SVal val)5780b57cec5SDimitry Andric bool ScanReachableSymbols::scan(SVal val) {
579bdd1243dSDimitry Andric if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>())
5800b57cec5SDimitry Andric return scan(X->getRegion());
5810b57cec5SDimitry Andric
582bdd1243dSDimitry Andric if (std::optional<nonloc::LazyCompoundVal> X =
5830b57cec5SDimitry Andric val.getAs<nonloc::LazyCompoundVal>())
5840b57cec5SDimitry Andric return scan(*X);
5850b57cec5SDimitry Andric
586bdd1243dSDimitry Andric if (std::optional<nonloc::LocAsInteger> X = val.getAs<nonloc::LocAsInteger>())
5870b57cec5SDimitry Andric return scan(X->getLoc());
5880b57cec5SDimitry Andric
5890b57cec5SDimitry Andric if (SymbolRef Sym = val.getAsSymbol())
5900b57cec5SDimitry Andric return scan(Sym);
5910b57cec5SDimitry Andric
592bdd1243dSDimitry Andric if (std::optional<nonloc::CompoundVal> X = val.getAs<nonloc::CompoundVal>())
5930b57cec5SDimitry Andric return scan(*X);
5940b57cec5SDimitry Andric
5950b57cec5SDimitry Andric return true;
5960b57cec5SDimitry Andric }
5970b57cec5SDimitry Andric
scan(const MemRegion * R)5980b57cec5SDimitry Andric bool ScanReachableSymbols::scan(const MemRegion *R) {
5990b57cec5SDimitry Andric if (isa<MemSpaceRegion>(R))
6000b57cec5SDimitry Andric return true;
6010b57cec5SDimitry Andric
6020b57cec5SDimitry Andric bool wasVisited = !visited.insert(R).second;
6030b57cec5SDimitry Andric if (wasVisited)
6040b57cec5SDimitry Andric return true;
6050b57cec5SDimitry Andric
6060b57cec5SDimitry Andric if (!visitor.VisitMemRegion(R))
6070b57cec5SDimitry Andric return false;
6080b57cec5SDimitry Andric
6090b57cec5SDimitry Andric // If this is a symbolic region, visit the symbol for the region.
6100b57cec5SDimitry Andric if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))
6110b57cec5SDimitry Andric if (!visitor.VisitSymbol(SR->getSymbol()))
6120b57cec5SDimitry Andric return false;
6130b57cec5SDimitry Andric
6140b57cec5SDimitry Andric // If this is a subregion, also visit the parent regions.
6150b57cec5SDimitry Andric if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {
6160b57cec5SDimitry Andric const MemRegion *Super = SR->getSuperRegion();
6170b57cec5SDimitry Andric if (!scan(Super))
6180b57cec5SDimitry Andric return false;
6190b57cec5SDimitry Andric
6200b57cec5SDimitry Andric // When we reach the topmost region, scan all symbols in it.
6210b57cec5SDimitry Andric if (isa<MemSpaceRegion>(Super)) {
6220b57cec5SDimitry Andric StoreManager &StoreMgr = state->getStateManager().getStoreManager();
6230b57cec5SDimitry Andric if (!StoreMgr.scanReachableSymbols(state->getStore(), SR, *this))
6240b57cec5SDimitry Andric return false;
6250b57cec5SDimitry Andric }
6260b57cec5SDimitry Andric }
6270b57cec5SDimitry Andric
6280b57cec5SDimitry Andric // Regions captured by a block are also implicitly reachable.
6290b57cec5SDimitry Andric if (const BlockDataRegion *BDR = dyn_cast<BlockDataRegion>(R)) {
630*fe013be4SDimitry Andric for (auto Var : BDR->referenced_vars()) {
631*fe013be4SDimitry Andric if (!scan(Var.getCapturedRegion()))
6320b57cec5SDimitry Andric return false;
6330b57cec5SDimitry Andric }
6340b57cec5SDimitry Andric }
6350b57cec5SDimitry Andric
6360b57cec5SDimitry Andric return true;
6370b57cec5SDimitry Andric }
6380b57cec5SDimitry Andric
scanReachableSymbols(SVal val,SymbolVisitor & visitor) const6390b57cec5SDimitry Andric bool ProgramState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const {
6400b57cec5SDimitry Andric ScanReachableSymbols S(this, visitor);
6410b57cec5SDimitry Andric return S.scan(val);
6420b57cec5SDimitry Andric }
6430b57cec5SDimitry Andric
scanReachableSymbols(llvm::iterator_range<region_iterator> Reachable,SymbolVisitor & visitor) const6440b57cec5SDimitry Andric bool ProgramState::scanReachableSymbols(
6450b57cec5SDimitry Andric llvm::iterator_range<region_iterator> Reachable,
6460b57cec5SDimitry Andric SymbolVisitor &visitor) const {
6470b57cec5SDimitry Andric ScanReachableSymbols S(this, visitor);
6480b57cec5SDimitry Andric for (const MemRegion *R : Reachable) {
6490b57cec5SDimitry Andric if (!S.scan(R))
6500b57cec5SDimitry Andric return false;
6510b57cec5SDimitry Andric }
6520b57cec5SDimitry Andric return true;
6530b57cec5SDimitry Andric }
654