brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.9 KiB · c4790b0 Raw
686 lines · cpp
1//= ProgramState.cpp - Path-Sensitive "State" for tracking values --*- C++ -*--=2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9//  This file implements ProgramState and ProgramStateManager.10//11//===----------------------------------------------------------------------===//12 13#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"14#include "clang/Analysis/CFG.h"15#include "clang/Basic/JsonSupport.h"16#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"17#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"18#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h"19#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"20#include "llvm/Support/raw_ostream.h"21#include <optional>22 23using namespace clang;24using namespace ento;25 26namespace clang { namespace  ento {27/// Increments the number of times this state is referenced.28 29void ProgramStateRetain(const ProgramState *state) {30  ++const_cast<ProgramState*>(state)->refCount;31}32 33/// Decrement the number of times this state is referenced.34void ProgramStateRelease(const ProgramState *state) {35  assert(state->refCount > 0);36  ProgramState *s = const_cast<ProgramState*>(state);37  if (--s->refCount == 0) {38    ProgramStateManager &Mgr = s->getStateManager();39    Mgr.StateSet.RemoveNode(s);40    s->~ProgramState();41    Mgr.freeStates.push_back(s);42  }43}44}}45 46ProgramState::ProgramState(ProgramStateManager *mgr, const Environment& env,47                 StoreRef st, GenericDataMap gdm)48  : stateMgr(mgr),49    Env(env),50    store(st.getStore()),51    GDM(gdm),52    refCount(0) {53  stateMgr->getStoreManager().incrementReferenceCount(store);54}55 56ProgramState::ProgramState(const ProgramState &RHS)57    : stateMgr(RHS.stateMgr), Env(RHS.Env), store(RHS.store), GDM(RHS.GDM),58      PosteriorlyOverconstrained(RHS.PosteriorlyOverconstrained), refCount(0) {59  stateMgr->getStoreManager().incrementReferenceCount(store);60}61 62ProgramState::~ProgramState() {63  if (store)64    stateMgr->getStoreManager().decrementReferenceCount(store);65}66 67int64_t ProgramState::getID() const {68  return getStateManager().Alloc.identifyKnownAlignedObject<ProgramState>(this);69}70 71ProgramStateManager::ProgramStateManager(ASTContext &Ctx,72                                         StoreManagerCreator CreateSMgr,73                                         ConstraintManagerCreator CreateCMgr,74                                         llvm::BumpPtrAllocator &alloc,75                                         ExprEngine *ExprEng)76  : Eng(ExprEng), EnvMgr(alloc), GDMFactory(alloc),77    svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)),78    CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) {79  StoreMgr = (*CreateSMgr)(*this);80  ConstraintMgr = (*CreateCMgr)(*this, ExprEng);81}82 83 84ProgramStateManager::~ProgramStateManager() {85  for (GDMContextsTy::iterator I=GDMContexts.begin(), E=GDMContexts.end();86       I!=E; ++I)87    I->second.second(I->second.first);88}89 90ProgramStateRef ProgramStateManager::removeDeadBindingsFromEnvironmentAndStore(91    ProgramStateRef state, const StackFrameContext *LCtx,92    SymbolReaper &SymReaper) {93 94  // This code essentially performs a "mark-and-sweep" of the VariableBindings.95  // The roots are any Block-level exprs and Decls that our liveness algorithm96  // tells us are live.  We then see what Decls they may reference, and keep97  // those around.  This code more than likely can be made faster, and the98  // frequency of which this method is called should be experimented with99  // for optimum performance.100  ProgramState NewState = *state;101 102  NewState.Env = EnvMgr.removeDeadBindings(NewState.Env, SymReaper, state);103 104  // Clean up the store.105  StoreRef newStore = StoreMgr->removeDeadBindings(NewState.getStore(), LCtx,106                                                   SymReaper);107  NewState.setStore(newStore);108  SymReaper.setReapedStore(newStore);109 110  return getPersistentState(NewState);111}112 113ProgramStateRef ProgramState::bindLoc(Loc LV,114                                      SVal V,115                                      const LocationContext *LCtx,116                                      bool notifyChanges) const {117  ProgramStateManager &Mgr = getStateManager();118  ExprEngine &Eng = Mgr.getOwningEngine();119  ProgramStateRef State = makeWithStore(Mgr.StoreMgr->Bind(getStore(), LV, V));120  const MemRegion *MR = LV.getAsRegion();121 122  if (MR && notifyChanges)123    return Eng.processRegionChange(State, MR, LCtx);124 125  return State;126}127 128ProgramStateRef129ProgramState::bindDefaultInitial(SVal loc, SVal V,130                                 const LocationContext *LCtx) const {131  ProgramStateManager &Mgr = getStateManager();132  const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();133  BindResult BindRes = Mgr.StoreMgr->BindDefaultInitial(getStore(), R, V);134  ProgramStateRef State = makeWithStore(BindRes);135  return Mgr.getOwningEngine().processRegionChange(State, R, LCtx);136}137 138ProgramStateRef139ProgramState::bindDefaultZero(SVal loc, const LocationContext *LCtx) const {140  ProgramStateManager &Mgr = getStateManager();141  const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion();142  BindResult BindRes = Mgr.StoreMgr->BindDefaultZero(getStore(), R);143  ProgramStateRef State = makeWithStore(BindRes);144  return Mgr.getOwningEngine().processRegionChange(State, R, LCtx);145}146 147typedef ArrayRef<const MemRegion *> RegionList;148typedef ArrayRef<SVal> ValueList;149 150ProgramStateRef ProgramState::invalidateRegions(151    RegionList Regions, ConstCFGElementRef Elem, unsigned Count,152    const LocationContext *LCtx, bool CausedByPointerEscape,153    InvalidatedSymbols *IS, const CallEvent *Call,154    RegionAndSymbolInvalidationTraits *ITraits) const {155  SmallVector<SVal, 8> Values;156  for (const MemRegion *Reg : Regions)157    Values.push_back(loc::MemRegionVal(Reg));158 159  return invalidateRegions(Values, Elem, Count, LCtx, CausedByPointerEscape, IS,160                           Call, ITraits);161}162 163ProgramStateRef ProgramState::invalidateRegions(164    ValueList Values, ConstCFGElementRef Elem, unsigned Count,165    const LocationContext *LCtx, bool CausedByPointerEscape,166    InvalidatedSymbols *IS, const CallEvent *Call,167    RegionAndSymbolInvalidationTraits *ITraits) const {168 169  ProgramStateManager &Mgr = getStateManager();170  ExprEngine &Eng = Mgr.getOwningEngine();171 172  InvalidatedSymbols InvalidatedSyms;173  if (!IS)174    IS = &InvalidatedSyms;175 176  RegionAndSymbolInvalidationTraits ITraitsLocal;177  if (!ITraits)178    ITraits = &ITraitsLocal;179 180  StoreManager::InvalidatedRegions TopLevelInvalidated;181  StoreManager::InvalidatedRegions Invalidated;182  const StoreRef &NewStore = Mgr.StoreMgr->invalidateRegions(183      getStore(), Values, Elem, Count, LCtx, Call, *IS, *ITraits,184      &TopLevelInvalidated, &Invalidated);185 186  ProgramStateRef NewState = makeWithStore(NewStore);187 188  if (CausedByPointerEscape) {189    NewState = Eng.notifyCheckersOfPointerEscape(190        NewState, IS, TopLevelInvalidated, Call, *ITraits);191  }192 193  return Eng.processRegionChanges(NewState, IS, TopLevelInvalidated,194                                  Invalidated, LCtx, Call);195}196 197ProgramStateRef ProgramState::killBinding(Loc LV) const {198  Store OldStore = getStore();199  const StoreRef &newStore =200    getStateManager().StoreMgr->killBinding(OldStore, LV);201 202  if (newStore.getStore() == OldStore)203    return this;204 205  return makeWithStore(newStore);206}207 208/// We should never form a MemRegion that would wrap a TypedValueRegion of a209/// reference type. What we actually wanted was to create a MemRegion refering210/// to the pointee of that reference.211SVal ProgramState::desugarReference(SVal Val) const {212  const auto *TyReg = dyn_cast_or_null<TypedValueRegion>(Val.getAsRegion());213  if (!TyReg || !TyReg->getValueType()->isReferenceType())214    return Val;215  return getSVal(TyReg);216}217 218/// SymbolicRegions are expected to be wrapped by an ElementRegion as a219/// canonical representation. As a canonical representation, SymbolicRegions220/// should be wrapped by ElementRegions before getting a FieldRegion.221/// See f8643a9b31c4029942f67d4534c9139b45173504 why.222SVal ProgramState::wrapSymbolicRegion(SVal Val) const {223  const auto *BaseReg = dyn_cast_or_null<SymbolicRegion>(Val.getAsRegion());224  if (!BaseReg)225    return Val;226 227  StoreManager &SM = getStateManager().getStoreManager();228  QualType ElemTy = BaseReg->getPointeeStaticType();229  return loc::MemRegionVal{SM.GetElementZeroRegion(BaseReg, ElemTy)};230}231 232ProgramStateRef233ProgramState::enterStackFrame(const CallEvent &Call,234                              const StackFrameContext *CalleeCtx) const {235  return makeWithStore(236      getStateManager().StoreMgr->enterStackFrame(getStore(), Call, CalleeCtx));237}238 239SVal ProgramState::getSelfSVal(const LocationContext *LCtx) const {240  const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl();241  if (!SelfDecl)242    return SVal();243  return getSVal(getRegion(SelfDecl, LCtx));244}245 246SVal ProgramState::getSValAsScalarOrLoc(const MemRegion *R) const {247  // We only want to do fetches from regions that we can actually bind248  // values.  For example, SymbolicRegions of type 'id<...>' cannot249  // have direct bindings (but their can be bindings on their subregions).250  if (!R->isBoundable())251    return UnknownVal();252 253  if (const TypedValueRegion *TR = dyn_cast<TypedValueRegion>(R)) {254    QualType T = TR->getValueType();255    if (Loc::isLocType(T) || T->isIntegralOrEnumerationType())256      return getSVal(R);257  }258 259  return UnknownVal();260}261 262SVal ProgramState::getSVal(Loc location, QualType T) const {263  SVal V = getRawSVal(location, T);264 265  // If 'V' is a symbolic value that is *perfectly* constrained to266  // be a constant value, use that value instead to lessen the burden267  // on later analysis stages (so we have less symbolic values to reason268  // about).269  // We only go into this branch if we can convert the APSInt value we have270  // to the type of T, which is not always the case (e.g. for void).271  if (!T.isNull() && (T->isIntegralOrEnumerationType() || Loc::isLocType(T))) {272    if (SymbolRef sym = V.getAsSymbol()) {273      if (const llvm::APSInt *Int = getStateManager()274                                    .getConstraintManager()275                                    .getSymVal(this, sym)) {276        // FIXME: Because we don't correctly model (yet) sign-extension277        // and truncation of symbolic values, we need to convert278        // the integer value to the correct signedness and bitwidth.279        //280        // This shows up in the following:281        //282        //   char foo();283        //   unsigned x = foo();284        //   if (x == 54)285        //     ...286        //287        //  The symbolic value stored to 'x' is actually the conjured288        //  symbol for the call to foo(); the type of that symbol is 'char',289        //  not unsigned.290        APSIntPtr NewV = getBasicVals().Convert(T, *Int);291        if (V.getAs<Loc>())292          return loc::ConcreteInt(NewV);293        return nonloc::ConcreteInt(NewV);294      }295    }296  }297 298  return V;299}300 301ProgramStateRef ProgramState::BindExpr(const Stmt *S,302                                           const LocationContext *LCtx,303                                           SVal V, bool Invalidate) const{304  Environment NewEnv =305    getStateManager().EnvMgr.bindExpr(Env, EnvironmentEntry(S, LCtx), V,306                                      Invalidate);307  if (NewEnv == Env)308    return this;309 310  ProgramState NewSt = *this;311  NewSt.Env = NewEnv;312  return getStateManager().getPersistentState(NewSt);313}314 315[[nodiscard]] std::pair<ProgramStateRef, ProgramStateRef>316ProgramState::assumeInBoundDual(DefinedOrUnknownSVal Idx,317                                DefinedOrUnknownSVal UpperBound,318                                QualType indexTy) const {319  if (Idx.isUnknown() || UpperBound.isUnknown())320    return {this, this};321 322  // Build an expression for 0 <= Idx < UpperBound.323  // This is the same as Idx + MIN < UpperBound + MIN, if overflow is allowed.324  // FIXME: This should probably be part of SValBuilder.325  ProgramStateManager &SM = getStateManager();326  SValBuilder &svalBuilder = SM.getSValBuilder();327  ASTContext &Ctx = svalBuilder.getContext();328 329  // Get the offset: the minimum value of the array index type.330  BasicValueFactory &BVF = svalBuilder.getBasicValueFactory();331  if (indexTy.isNull())332    indexTy = svalBuilder.getArrayIndexType();333  nonloc::ConcreteInt Min(BVF.getMinValue(indexTy));334 335  // Adjust the index.336  SVal newIdx = svalBuilder.evalBinOpNN(this, BO_Add,337                                        Idx.castAs<NonLoc>(), Min, indexTy);338  if (newIdx.isUnknownOrUndef())339    return {this, this};340 341  // Adjust the upper bound.342  SVal newBound =343    svalBuilder.evalBinOpNN(this, BO_Add, UpperBound.castAs<NonLoc>(),344                            Min, indexTy);345 346  if (newBound.isUnknownOrUndef())347    return {this, this};348 349  // Build the actual comparison.350  SVal inBound = svalBuilder.evalBinOpNN(this, BO_LT, newIdx.castAs<NonLoc>(),351                                         newBound.castAs<NonLoc>(), Ctx.IntTy);352  if (inBound.isUnknownOrUndef())353    return {this, this};354 355  // Finally, let the constraint manager take care of it.356  ConstraintManager &CM = SM.getConstraintManager();357  return CM.assumeDual(this, inBound.castAs<DefinedSVal>());358}359 360ProgramStateRef ProgramState::assumeInBound(DefinedOrUnknownSVal Idx,361                                            DefinedOrUnknownSVal UpperBound,362                                            bool Assumption,363                                            QualType indexTy) const {364  std::pair<ProgramStateRef, ProgramStateRef> R =365      assumeInBoundDual(Idx, UpperBound, indexTy);366  return Assumption ? R.first : R.second;367}368 369ConditionTruthVal ProgramState::isNonNull(SVal V) const {370  ConditionTruthVal IsNull = isNull(V);371  if (IsNull.isUnderconstrained())372    return IsNull;373  return ConditionTruthVal(!IsNull.getValue());374}375 376ConditionTruthVal ProgramState::areEqual(SVal Lhs, SVal Rhs) const {377  return stateMgr->getSValBuilder().areEqual(this, Lhs, Rhs);378}379 380ConditionTruthVal ProgramState::isNull(SVal V) const {381  if (V.isZeroConstant())382    return true;383 384  if (V.isConstant())385    return false;386 387  SymbolRef Sym = V.getAsSymbol(/* IncludeBaseRegion */ true);388  if (!Sym)389    return ConditionTruthVal();390 391  return getStateManager().ConstraintMgr->isNull(this, Sym);392}393 394ProgramStateRef ProgramStateManager::getInitialState(const LocationContext *InitLoc) {395  ProgramState State(this,396                EnvMgr.getInitialEnvironment(),397                StoreMgr->getInitialStore(InitLoc),398                GDMFactory.getEmptyMap());399 400  return getPersistentState(State);401}402 403ProgramStateRef ProgramStateManager::getPersistentStateWithGDM(404                                                     ProgramStateRef FromState,405                                                     ProgramStateRef GDMState) {406  ProgramState NewState(*FromState);407  NewState.GDM = GDMState->GDM;408  return getPersistentState(NewState);409}410 411ProgramStateRef ProgramStateManager::getPersistentState(ProgramState &State) {412 413  llvm::FoldingSetNodeID ID;414  State.Profile(ID);415  void *InsertPos;416 417  if (ProgramState *I = StateSet.FindNodeOrInsertPos(ID, InsertPos))418    return I;419 420  ProgramState *newState = nullptr;421  if (!freeStates.empty()) {422    newState = freeStates.back();423    freeStates.pop_back();424  }425  else {426    newState = Alloc.Allocate<ProgramState>();427  }428  new (newState) ProgramState(State);429  StateSet.InsertNode(newState, InsertPos);430  return newState;431}432 433ProgramStateRef ProgramState::makeWithStore(const StoreRef &store) const {434  ProgramState NewSt(*this);435  NewSt.setStore(store);436  return getStateManager().getPersistentState(NewSt);437}438 439ProgramStateRef ProgramState::makeWithStore(const BindResult &BindRes) const {440  ExprEngine &Eng = getStateManager().getOwningEngine();441  ProgramStateRef State = makeWithStore(BindRes.ResultingStore);442 443  // We must always notify the checkers for failing binds because otherwise they444  // may keep stale traits for these symbols.445  // Eg., Malloc checker may report leaks if we failed to bind that symbol.446  if (BindRes.FailedToBindValues.empty())447    return State;448  return Eng.escapeValues(State, BindRes.FailedToBindValues, PSK_EscapeOnBind);449}450 451ProgramStateRef ProgramState::cloneAsPosteriorlyOverconstrained() const {452  ProgramState NewSt(*this);453  NewSt.PosteriorlyOverconstrained = true;454  return getStateManager().getPersistentState(NewSt);455}456 457void ProgramState::setStore(const StoreRef &newStore) {458  Store newStoreStore = newStore.getStore();459  if (newStoreStore)460    stateMgr->getStoreManager().incrementReferenceCount(newStoreStore);461  if (store)462    stateMgr->getStoreManager().decrementReferenceCount(store);463  store = newStoreStore;464}465 466SVal ProgramState::getLValue(const FieldDecl *D, SVal Base) const {467  Base = desugarReference(Base);468  Base = wrapSymbolicRegion(Base);469  return getStateManager().StoreMgr->getLValueField(D, Base);470}471 472SVal ProgramState::getLValue(const IndirectFieldDecl *D, SVal Base) const {473  StoreManager &SM = *getStateManager().StoreMgr;474  Base = desugarReference(Base);475  Base = wrapSymbolicRegion(Base);476 477  // FIXME: This should work with `SM.getLValueField(D->getAnonField(), Base)`,478  // but that would break some tests. There is probably a bug somewhere that it479  // would expose.480  for (const auto *I : D->chain()) {481    Base = SM.getLValueField(cast<FieldDecl>(I), Base);482  }483  return Base;484}485 486//===----------------------------------------------------------------------===//487//  State pretty-printing.488//===----------------------------------------------------------------------===//489 490void ProgramState::printJson(raw_ostream &Out, const LocationContext *LCtx,491                             const char *NL, unsigned int Space,492                             bool IsDot) const {493  Indent(Out, Space, IsDot) << "\"program_state\": {" << NL;494  ++Space;495 496  ProgramStateManager &Mgr = getStateManager();497 498  // Print the store.499  Mgr.getStoreManager().printJson(Out, getStore(), NL, Space, IsDot);500 501  // Print out the environment.502  Env.printJson(Out, Mgr.getContext(), LCtx, NL, Space, IsDot);503 504  // Print out the constraints.505  Mgr.getConstraintManager().printJson(Out, this, NL, Space, IsDot);506 507  // Print out the tracked dynamic types.508  printDynamicTypeInfoJson(Out, this, NL, Space, IsDot);509 510  // Print checker-specific data.511  Mgr.getOwningEngine().printJson(Out, this, LCtx, NL, Space, IsDot);512 513  --Space;514  Indent(Out, Space, IsDot) << '}';515}516 517void ProgramState::printDOT(raw_ostream &Out, const LocationContext *LCtx,518                            unsigned int Space) const {519  printJson(Out, LCtx, /*NL=*/"\\l", Space, /*IsDot=*/true);520}521 522LLVM_DUMP_METHOD void ProgramState::dump() const {523  printJson(llvm::errs());524}525 526AnalysisManager& ProgramState::getAnalysisManager() const {527  return stateMgr->getOwningEngine().getAnalysisManager();528}529 530//===----------------------------------------------------------------------===//531// Generic Data Map.532//===----------------------------------------------------------------------===//533 534void *const* ProgramState::FindGDM(void *K) const {535  return GDM.lookup(K);536}537 538void*539ProgramStateManager::FindGDMContext(void *K,540                               void *(*CreateContext)(llvm::BumpPtrAllocator&),541                               void (*DeleteContext)(void*)) {542 543  std::pair<void*, void (*)(void*)>& p = GDMContexts[K];544  if (!p.first) {545    p.first = CreateContext(Alloc);546    p.second = DeleteContext;547  }548 549  return p.first;550}551 552ProgramStateRef ProgramStateManager::addGDM(ProgramStateRef St, void *Key, void *Data){553  ProgramState::GenericDataMap M1 = St->getGDM();554  ProgramState::GenericDataMap M2 = GDMFactory.add(M1, Key, Data);555 556  if (M1 == M2)557    return St;558 559  ProgramState NewSt = *St;560  NewSt.GDM = M2;561  return getPersistentState(NewSt);562}563 564ProgramStateRef ProgramStateManager::removeGDM(ProgramStateRef state, void *Key) {565  ProgramState::GenericDataMap OldM = state->getGDM();566  ProgramState::GenericDataMap NewM = GDMFactory.remove(OldM, Key);567 568  if (NewM == OldM)569    return state;570 571  ProgramState NewState = *state;572  NewState.GDM = NewM;573  return getPersistentState(NewState);574}575 576bool ScanReachableSymbols::scan(nonloc::LazyCompoundVal val) {577  bool wasVisited = !visited.insert(val.getCVData()).second;578  if (wasVisited)579    return true;580 581  StoreManager &StoreMgr = state->getStateManager().getStoreManager();582  // FIXME: We don't really want to use getBaseRegion() here because pointer583  // arithmetic doesn't apply, but scanReachableSymbols only accepts base584  // regions right now.585  const MemRegion *R = val.getRegion()->getBaseRegion();586  return StoreMgr.scanReachableSymbols(val.getStore(), R, *this);587}588 589bool ScanReachableSymbols::scan(nonloc::CompoundVal val) {590  for (SVal V : val)591    if (!scan(V))592      return false;593 594  return true;595}596 597bool ScanReachableSymbols::scan(const SymExpr *sym) {598  for (SymbolRef SubSym : sym->symbols()) {599    bool wasVisited = !visited.insert(SubSym).second;600    if (wasVisited)601      continue;602 603    if (!visitor.VisitSymbol(SubSym))604      return false;605  }606 607  return true;608}609 610bool ScanReachableSymbols::scan(SVal val) {611  if (std::optional<loc::MemRegionVal> X = val.getAs<loc::MemRegionVal>())612    return scan(X->getRegion());613 614  if (std::optional<nonloc::LazyCompoundVal> X =615          val.getAs<nonloc::LazyCompoundVal>())616    return scan(*X);617 618  if (std::optional<nonloc::LocAsInteger> X = val.getAs<nonloc::LocAsInteger>())619    return scan(X->getLoc());620 621  if (SymbolRef Sym = val.getAsSymbol())622    return scan(Sym);623 624  if (std::optional<nonloc::CompoundVal> X = val.getAs<nonloc::CompoundVal>())625    return scan(*X);626 627  return true;628}629 630bool ScanReachableSymbols::scan(const MemRegion *R) {631  if (isa<MemSpaceRegion>(R))632    return true;633 634  bool wasVisited = !visited.insert(R).second;635  if (wasVisited)636    return true;637 638  if (!visitor.VisitMemRegion(R))639    return false;640 641  // If this is a symbolic region, visit the symbol for the region.642  if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R))643    if (!visitor.VisitSymbol(SR->getSymbol()))644      return false;645 646  // If this is a subregion, also visit the parent regions.647  if (const SubRegion *SR = dyn_cast<SubRegion>(R)) {648    const MemRegion *Super = SR->getSuperRegion();649    if (!scan(Super))650      return false;651 652    // When we reach the topmost region, scan all symbols in it.653    if (isa<MemSpaceRegion>(Super)) {654      StoreManager &StoreMgr = state->getStateManager().getStoreManager();655      if (!StoreMgr.scanReachableSymbols(state->getStore(), SR, *this))656        return false;657    }658  }659 660  // Regions captured by a block are also implicitly reachable.661  if (const BlockDataRegion *BDR = dyn_cast<BlockDataRegion>(R)) {662    for (auto Var : BDR->referenced_vars()) {663      if (!scan(Var.getCapturedRegion()))664        return false;665    }666  }667 668  return true;669}670 671bool ProgramState::scanReachableSymbols(SVal val, SymbolVisitor& visitor) const {672  ScanReachableSymbols S(this, visitor);673  return S.scan(val);674}675 676bool ProgramState::scanReachableSymbols(677    llvm::iterator_range<region_iterator> Reachable,678    SymbolVisitor &visitor) const {679  ScanReachableSymbols S(this, visitor);680  for (const MemRegion *R : Reachable) {681    if (!S.scan(R))682      return false;683  }684  return true;685}686