diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core/RegionStore.cpp')
-rw-r--r-- | lib/StaticAnalyzer/Core/RegionStore.cpp | 175 |
1 files changed, 102 insertions, 73 deletions
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index db6449e6d5f34..b2339be4f263e 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -17,6 +17,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Basic/TargetInfo.h" @@ -61,7 +62,9 @@ private: : P(r, k), Data(offset) { assert(r && "Must have known regions."); assert(getOffset() == offset && "Failed to store offset"); - assert((r == r->getBaseRegion() || isa<ObjCIvarRegion>(r)) && "Not a base"); + assert((r == r->getBaseRegion() || isa<ObjCIvarRegion>(r) || + isa <CXXDerivedObjectRegion>(r)) && + "Not a base"); } public: @@ -308,7 +311,7 @@ public: //===----------------------------------------------------------------------===// namespace { -class invalidateRegionsWorker; +class InvalidateRegionsWorker; class RegionStoreManager : public StoreManager { public: @@ -335,7 +338,7 @@ private: /// A helper used to populate the work list with the given set of /// regions. - void populateWorkList(invalidateRegionsWorker &W, + void populateWorkList(InvalidateRegionsWorker &W, ArrayRef<SVal> Values, InvalidatedRegions *TopLevelRegions); @@ -344,11 +347,9 @@ public: : StoreManager(mgr), Features(f), RBFactory(mgr.getAllocator()), CBFactory(mgr.getAllocator()), SmallStructLimit(0) { - if (SubEngine *Eng = StateMgr.getOwningEngine()) { - AnalyzerOptions &Options = Eng->getAnalysisManager().options; - SmallStructLimit = - Options.getOptionAsInteger("region-store-small-struct-limit", 2); - } + SubEngine &Eng = StateMgr.getOwningEngine(); + AnalyzerOptions &Options = Eng.getAnalysisManager().options; + SmallStructLimit = Options.RegionStoreSmallStructLimit; } @@ -598,8 +599,7 @@ public: // Part of public interface to class. RBFactory.getTreeFactory()); } - void print(Store store, raw_ostream &Out, const char* nl, - const char *sep) override; + void print(Store store, raw_ostream &Out, const char* nl) override; void iterBindings(Store store, BindingsHandler& f) override { RegionBindingsRef B = getRegionBindings(store); @@ -945,7 +945,7 @@ RegionStoreManager::removeSubRegionBindings(RegionBindingsConstRef B, } namespace { -class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker> +class InvalidateRegionsWorker : public ClusterAnalysis<InvalidateRegionsWorker> { const Expr *Ex; unsigned Count; @@ -955,7 +955,7 @@ class invalidateRegionsWorker : public ClusterAnalysis<invalidateRegionsWorker> StoreManager::InvalidatedRegions *Regions; GlobalsFilterKind GlobalsFilter; public: - invalidateRegionsWorker(RegionStoreManager &rm, + InvalidateRegionsWorker(RegionStoreManager &rm, ProgramStateManager &stateMgr, RegionBindingsRef b, const Expr *ex, unsigned count, @@ -964,7 +964,7 @@ public: RegionAndSymbolInvalidationTraits &ITraitsIn, StoreManager::InvalidatedRegions *r, GlobalsFilterKind GFK) - : ClusterAnalysis<invalidateRegionsWorker>(rm, stateMgr, b), + : ClusterAnalysis<InvalidateRegionsWorker>(rm, stateMgr, b), Ex(ex), Count(count), LCtx(lctx), IS(is), ITraits(ITraitsIn), Regions(r), GlobalsFilter(GFK) {} @@ -985,14 +985,14 @@ public: }; } -bool invalidateRegionsWorker::AddToWorkList(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) { +void InvalidateRegionsWorker::VisitBinding(SVal V) { // A symbol? Mark it touched by the invalidation. if (SymbolRef Sym = V.getAsSymbol()) IS.insert(Sym); @@ -1017,7 +1017,7 @@ void invalidateRegionsWorker::VisitBinding(SVal V) { } } -void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, +void InvalidateRegionsWorker::VisitCluster(const MemRegion *baseR, const ClusterBindings *C) { bool PreserveRegionsContents = @@ -1033,6 +1033,32 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, B = B.remove(baseR); } + if (const auto *TO = dyn_cast<TypedValueRegion>(baseR)) { + if (const auto *RD = TO->getValueType()->getAsCXXRecordDecl()) { + + // Lambdas can affect all static local variables without explicitly + // capturing those. + // We invalidate all static locals referenced inside the lambda body. + if (RD->isLambda() && RD->getLambdaCallOperator()->getBody()) { + using namespace ast_matchers; + + const char *DeclBind = "DeclBind"; + StatementMatcher RefToStatic = stmt(hasDescendant(declRefExpr( + to(varDecl(hasStaticStorageDuration()).bind(DeclBind))))); + auto Matches = + match(RefToStatic, *RD->getLambdaCallOperator()->getBody(), + RD->getASTContext()); + + for (BoundNodes &Match : Matches) { + auto *VD = Match.getNodeAs<VarDecl>(DeclBind); + const VarRegion *ToInvalidate = + RM.getRegionManager().getVarRegion(VD, LCtx); + AddToWorkList(ToInvalidate); + } + } + } + } + // BlockDataRegion? If so, invalidate captured variables that are passed // by reference. if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(baseR)) { @@ -1181,7 +1207,7 @@ void invalidateRegionsWorker::VisitCluster(const MemRegion *baseR, B = B.addBinding(baseR, BindingKey::Direct, V); } -bool invalidateRegionsWorker::isInitiallyIncludedGlobalRegion( +bool InvalidateRegionsWorker::isInitiallyIncludedGlobalRegion( const MemRegion *R) { switch (GlobalsFilter) { case GFK_None: @@ -1195,7 +1221,7 @@ bool invalidateRegionsWorker::isInitiallyIncludedGlobalRegion( llvm_unreachable("unknown globals filter"); } -bool invalidateRegionsWorker::includeEntireMemorySpace(const MemRegion *Base) { +bool InvalidateRegionsWorker::includeEntireMemorySpace(const MemRegion *Base) { if (isInitiallyIncludedGlobalRegion(Base)) return true; @@ -1229,7 +1255,7 @@ RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K, return B; } -void RegionStoreManager::populateWorkList(invalidateRegionsWorker &W, +void RegionStoreManager::populateWorkList(InvalidateRegionsWorker &W, ArrayRef<SVal> Values, InvalidatedRegions *TopLevelRegions) { for (ArrayRef<SVal>::iterator I = Values.begin(), @@ -1280,7 +1306,7 @@ RegionStoreManager::invalidateRegions(Store store, } RegionBindingsRef B = getRegionBindings(store); - invalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ITraits, + InvalidateRegionsWorker W(*this, StateMgr, B, Ex, Count, LCtx, IS, ITraits, Invalidated, GlobalsFilter); // Scan the bindings and generate the clusters. @@ -1302,11 +1328,11 @@ RegionStoreManager::invalidateRegions(Store store, case GFK_All: B = invalidateGlobalRegion(MemRegion::GlobalInternalSpaceRegionKind, Ex, Count, LCtx, B, Invalidated); - // FALLTHROUGH + LLVM_FALLTHROUGH; case GFK_SystemOnly: B = invalidateGlobalRegion(MemRegion::GlobalSystemSpaceRegionKind, Ex, Count, LCtx, B, Invalidated); - // FALLTHROUGH + LLVM_FALLTHROUGH; case GFK_None: break; } @@ -2363,40 +2389,45 @@ RegionStoreManager::bindAggregate(RegionBindingsConstRef B, //===----------------------------------------------------------------------===// namespace { -class removeDeadBindingsWorker : - public ClusterAnalysis<removeDeadBindingsWorker> { - SmallVector<const SymbolicRegion*, 12> Postponed; +class RemoveDeadBindingsWorker + : public ClusterAnalysis<RemoveDeadBindingsWorker> { + using ChildrenListTy = SmallVector<const SymbolDerived *, 4>; + using MapParentsToDerivedTy = llvm::DenseMap<SymbolRef, ChildrenListTy>; + + MapParentsToDerivedTy ParentsToDerived; SymbolReaper &SymReaper; const StackFrameContext *CurrentLCtx; public: - removeDeadBindingsWorker(RegionStoreManager &rm, + RemoveDeadBindingsWorker(RegionStoreManager &rm, ProgramStateManager &stateMgr, RegionBindingsRef b, SymbolReaper &symReaper, const StackFrameContext *LCtx) - : ClusterAnalysis<removeDeadBindingsWorker>(rm, stateMgr, b), + : ClusterAnalysis<RemoveDeadBindingsWorker>(rm, stateMgr, b), SymReaper(symReaper), CurrentLCtx(LCtx) {} // Called by ClusterAnalysis. void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C); void VisitCluster(const MemRegion *baseR, const ClusterBindings *C); - using ClusterAnalysis<removeDeadBindingsWorker>::VisitCluster; + using ClusterAnalysis<RemoveDeadBindingsWorker>::VisitCluster; using ClusterAnalysis::AddToWorkList; bool AddToWorkList(const MemRegion *R); - bool UpdatePostponed(); void VisitBinding(SVal V); + +private: + void populateWorklistFromSymbol(SymbolRef s); }; } -bool removeDeadBindingsWorker::AddToWorkList(const MemRegion *R) { +bool RemoveDeadBindingsWorker::AddToWorkList(const MemRegion *R) { const MemRegion *BaseR = R->getBaseRegion(); return AddToWorkList(WorkListElement(BaseR), getCluster(BaseR)); } -void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, +void RemoveDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C) { if (const VarRegion *VR = dyn_cast<VarRegion>(baseR)) { @@ -2407,10 +2438,11 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, } if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(baseR)) { - if (SymReaper.isLive(SR->getSymbol())) + if (SymReaper.isLive(SR->getSymbol())) { AddToWorkList(SR, &C); - else - Postponed.push_back(SR); + } else if (const auto *SD = dyn_cast<SymbolDerived>(SR->getSymbol())) { + ParentsToDerived[SD->getParentSymbol()].push_back(SD); + } return; } @@ -2422,7 +2454,7 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, // CXXThisRegion in the current or parent location context is live. if (const CXXThisRegion *TR = dyn_cast<CXXThisRegion>(baseR)) { - const StackArgumentsSpaceRegion *StackReg = + const auto *StackReg = cast<StackArgumentsSpaceRegion>(TR->getSuperRegion()); const StackFrameContext *RegCtx = StackReg->getStackFrame(); if (CurrentLCtx && @@ -2431,7 +2463,7 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, } } -void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR, +void RemoveDeadBindingsWorker::VisitCluster(const MemRegion *baseR, const ClusterBindings *C) { if (!C) return; @@ -2449,7 +2481,7 @@ void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR, } } -void removeDeadBindingsWorker::VisitBinding(SVal V) { +void RemoveDeadBindingsWorker::VisitBinding(SVal V) { // Is it a LazyCompoundVal? All referenced regions are live as well. if (Optional<nonloc::LazyCompoundVal> LCS = V.getAs<nonloc::LazyCompoundVal>()) { @@ -2467,6 +2499,15 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) { // If V is a region, then add it to the worklist. if (const MemRegion *R = V.getAsRegion()) { AddToWorkList(R); + + if (const auto *TVR = dyn_cast<TypedValueRegion>(R)) { + DefinedOrUnknownSVal RVS = + RM.getSValBuilder().getRegionValueSymbolVal(TVR); + if (const MemRegion *SR = RVS.getAsRegion()) { + AddToWorkList(SR); + } + } + SymReaper.markLive(R); // All regions captured by a block are also live. @@ -2480,34 +2521,37 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) { // Update the set of live symbols. - for (SymExpr::symbol_iterator SI = V.symbol_begin(), SE = V.symbol_end(); - SI!=SE; ++SI) + for (auto SI = V.symbol_begin(), SE = V.symbol_end(); SI != SE; ++SI) { + populateWorklistFromSymbol(*SI); + + for (const auto *SD : ParentsToDerived[*SI]) + populateWorklistFromSymbol(SD); + SymReaper.markLive(*SI); + } } -bool removeDeadBindingsWorker::UpdatePostponed() { - // See if any postponed SymbolicRegions are actually live now, after - // having done a scan. - bool changed = false; +void RemoveDeadBindingsWorker::populateWorklistFromSymbol(SymbolRef S) { + if (const auto *SD = dyn_cast<SymbolData>(S)) { + if (Loc::isLocType(SD->getType()) && !SymReaper.isLive(SD)) { + const SymbolicRegion *SR = RM.getRegionManager().getSymbolicRegion(SD); - for (SmallVectorImpl<const SymbolicRegion*>::iterator - I = Postponed.begin(), E = Postponed.end() ; I != E ; ++I) { - if (const SymbolicRegion *SR = *I) { - if (SymReaper.isLive(SR->getSymbol())) { - changed |= AddToWorkList(SR); - *I = nullptr; - } + if (B.contains(SR)) + AddToWorkList(SR); + + const SymbolicRegion *SHR = + RM.getRegionManager().getSymbolicHeapRegion(SD); + if (B.contains(SHR)) + AddToWorkList(SHR); } } - - return changed; } StoreRef RegionStoreManager::removeDeadBindings(Store store, const StackFrameContext *LCtx, SymbolReaper& SymReaper) { RegionBindingsRef B = getRegionBindings(store); - removeDeadBindingsWorker W(*this, StateMgr, B, SymReaper, LCtx); + RemoveDeadBindingsWorker W(*this, StateMgr, B, SymReaper, LCtx); W.GenerateClusters(); // Enqueue the region roots onto the worklist. @@ -2516,7 +2560,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store, W.AddToWorkList(*I); } - do W.RunWorkList(); while (W.UpdatePostponed()); + W.RunWorkList(); // We have now scanned the store, marking reachable regions and symbols // as live. We now remove all the regions that are dead from the store @@ -2525,24 +2569,9 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store, const MemRegion *Base = I.getKey(); // If the cluster has been visited, we know the region has been marked. - if (W.isVisited(Base)) - continue; - - // Remove the dead entry. - B = B.remove(Base); - - if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(Base)) - SymReaper.maybeDead(SymR->getSymbol()); - - // Mark all non-live symbols that this binding references as dead. - const ClusterBindings &Cluster = I.getData(); - for (ClusterBindings::iterator CI = Cluster.begin(), CE = Cluster.end(); - CI != CE; ++CI) { - SVal X = CI.getData(); - SymExpr::symbol_iterator SI = X.symbol_begin(), SE = X.symbol_end(); - for (; SI != SE; ++SI) - SymReaper.maybeDead(*SI); - } + // Otherwise, remove the dead entry. + if (!W.isVisited(Base)) + B = B.remove(Base); } return StoreRef(B.asStore(), *this); @@ -2553,7 +2582,7 @@ StoreRef RegionStoreManager::removeDeadBindings(Store store, //===----------------------------------------------------------------------===// void RegionStoreManager::print(Store store, raw_ostream &OS, - const char* nl, const char *sep) { + const char* nl) { RegionBindingsRef B = getRegionBindings(store); OS << "Store (direct and default bindings), " << B.asStore() |