diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2018-05-04 21:56:51 +0000 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2018-05-04 21:56:51 +0000 |
commit | 806486c7818ece98a00fb0ed988b2a3dd982f5c4 (patch) | |
tree | bce7cf1638c6883c6341260bc919705491682e52 /clang/lib/StaticAnalyzer/Core | |
parent | 2cd09d017a20d2cb9e1839fb99cb362ae995069c (diff) | |
download | bcm5719-llvm-806486c7818ece98a00fb0ed988b2a3dd982f5c4.tar.gz bcm5719-llvm-806486c7818ece98a00fb0ed988b2a3dd982f5c4.zip |
[analyzer] pr18953: Split C++ zero-initialization from default initialization.
The bindDefault() API of the ProgramState allows setting a default value
for reads from memory regions that were not preceded by writes.
It was used for implementing C++ zeroing constructors (i.e. default constructors
that boil down to setting all fields of the object to 0).
Because differences between zeroing consturctors and other forms of default
initialization have been piling up (in particular, zeroing constructors can be
called multiple times over the same object, probably even at the same offset,
requiring a careful and potentially slow cleanup of previous bindings in the
RegionStore), we split the API in two: bindDefaultInitial() for modeling
initial values and bindDefaultZero() for modeling zeroing constructors.
This fixes a few assertion failures from which the investigation originated.
The imperfect protection from both inability of the RegionStore to support
binding extents and lack of information in ASTRecordLayout has been loosened
because it's, well, imperfect, and it is unclear if it fixing more than it
was breaking.
Differential Revision: https://reviews.llvm.org/D46368
llvm-svn: 331561
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 4 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 5 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ProgramState.cpp | 25 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/RegionStore.cpp | 40 | ||||
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/Store.cpp | 4 |
5 files changed, 44 insertions, 34 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index d0ebb223e94..6956c6dbe83 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -348,7 +348,9 @@ ExprEngine::createTemporaryRegionIfNeeded(ProgramStateRef State, break; case SubobjectAdjustment::MemberPointerAdjustment: // FIXME: Unimplemented. - State = State->bindDefault(Reg, UnknownVal(), LC); + State = State->invalidateRegions(Reg, InitWithAdjustments, + currBldrCtx->blockCount(), LC, true, + nullptr, nullptr, nullptr); return State; } } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 9152b41e1e1..90a35f39324 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -375,9 +375,6 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, I != E; ++I) { ProgramStateRef State = (*I)->getState(); if (CE->requiresZeroInitialization()) { - // Type of the zero doesn't matter. - SVal ZeroVal = svalBuilder.makeZeroVal(getContext().CharTy); - // FIXME: Once we properly handle constructors in new-expressions, we'll // need to invalidate the region before setting a default value, to make // sure there aren't any lingering bindings around. This probably needs @@ -390,7 +387,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, // actually make things worse. Placement new makes this tricky as well, // since it's then possible to be initializing one part of a multi- // dimensional array. - State = State->bindDefault(loc::MemRegionVal(Target), ZeroVal, LCtx); + State = State->bindDefaultZero(loc::MemRegionVal(Target), LCtx); } State = addAllNecessaryTemporaryInfo(State, CC, LCtx, Target); diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index deb2e4a5074..141863d2ac8 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -126,16 +126,27 @@ ProgramStateRef ProgramState::bindLoc(Loc LV, return newState; } -ProgramStateRef ProgramState::bindDefault(SVal loc, - SVal V, - const LocationContext *LCtx) const { +ProgramStateRef +ProgramState::bindDefaultInitial(SVal loc, SVal V, + const LocationContext *LCtx) const { + ProgramStateManager &Mgr = getStateManager(); + const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion(); + const StoreRef &newStore = Mgr.StoreMgr->BindDefaultInitial(getStore(), R, V); + ProgramStateRef new_state = makeWithStore(newStore); + return Mgr.getOwningEngine() + ? Mgr.getOwningEngine()->processRegionChange(new_state, R, LCtx) + : new_state; +} + +ProgramStateRef +ProgramState::bindDefaultZero(SVal loc, const LocationContext *LCtx) const { ProgramStateManager &Mgr = getStateManager(); const MemRegion *R = loc.castAs<loc::MemRegionVal>().getRegion(); - const StoreRef &newStore = Mgr.StoreMgr->BindDefault(getStore(), R, V); + const StoreRef &newStore = Mgr.StoreMgr->BindDefaultZero(getStore(), R); ProgramStateRef new_state = makeWithStore(newStore); - return Mgr.getOwningEngine() ? - Mgr.getOwningEngine()->processRegionChange(new_state, R, LCtx) : - new_state; + return Mgr.getOwningEngine() + ? Mgr.getOwningEngine()->processRegionChange(new_state, R, LCtx) + : new_state; } typedef ArrayRef<const MemRegion *> RegionList; diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 7f2c1d58262..d4624c089da 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -409,8 +409,22 @@ public: // Part of public interface to class. RegionBindingsRef bind(RegionBindingsConstRef B, Loc LV, SVal V); - // BindDefault is only used to initialize a region with a default value. - StoreRef BindDefault(Store store, const MemRegion *R, SVal V) override { + // BindDefaultInitial is only used to initialize a region with + // a default value. + StoreRef BindDefaultInitial(Store store, const MemRegion *R, + SVal V) override { + RegionBindingsRef B = getRegionBindings(store); + // Use other APIs when you have to wipe the region that was initialized + // earlier. + assert(!(B.getDefaultBinding(R) || B.getDirectBinding(R)) && + "Double initialization!"); + B = B.addBinding(BindingKey::Make(R, BindingKey::Default), V); + return StoreRef(B.asImmutableMap().getRootWithoutRetain(), *this); + } + + // BindDefaultZero is used for zeroing constructors that may accidentally + // overwrite existing bindings. + StoreRef BindDefaultZero(Store store, const MemRegion *R) override { // FIXME: The offsets of empty bases can be tricky because of // of the so called "empty base class optimization". // If a base class has been optimized out @@ -420,24 +434,14 @@ public: // Part of public interface to class. // and trying to infer them from offsets/alignments // seems to be error-prone and non-trivial because of the trailing padding. // As a temporary mitigation we don't create bindings for empty bases. - if (R->getKind() == MemRegion::CXXBaseObjectRegionKind && - cast<CXXBaseObjectRegion>(R)->getDecl()->isEmpty()) - return StoreRef(store, *this); + if (const auto *BR = dyn_cast<CXXBaseObjectRegion>(R)) + if (BR->getDecl()->isEmpty()) + return StoreRef(store, *this); RegionBindingsRef B = getRegionBindings(store); - assert(!B.lookup(R, BindingKey::Direct)); - - BindingKey Key = BindingKey::Make(R, BindingKey::Default); - if (B.lookup(Key)) { - const SubRegion *SR = cast<SubRegion>(R); - assert(SR->getAsOffset().getOffset() == - SR->getSuperRegion()->getAsOffset().getOffset() && - "A default value must come from a super-region"); - B = removeSubRegionBindings(B, SR); - } else { - B = B.addBinding(Key, V); - } - + 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); } diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp index e78ac0fe007..eeafaf61084 100644 --- a/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -65,10 +65,6 @@ const ElementRegion *StoreManager::MakeElementRegion(const SubRegion *Base, return MRMgr.getElementRegion(EleTy, idx, Base, svalBuilder.getContext()); } -StoreRef StoreManager::BindDefault(Store store, const MemRegion *R, SVal V) { - return StoreRef(store, *this); -} - const ElementRegion *StoreManager::GetElementZeroRegion(const SubRegion *R, QualType T) { NonLoc idx = svalBuilder.makeZeroArrayIndex(); |