summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
diff options
context:
space:
mode:
authorArtem Dergachev <artem.dergachev@gmail.com>2018-06-01 01:59:48 +0000
committerArtem Dergachev <artem.dergachev@gmail.com>2018-06-01 01:59:48 +0000
commitf83d547989c2dab2353cafb4aafa3561e87449d1 (patch)
tree4a2bb58c1af915b48cb65d12e2799593f7653b68 /clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
parent9f6020bcc522c1a9613fafd2fd65ef6c915c388d (diff)
downloadbcm5719-llvm-f83d547989c2dab2353cafb4aafa3561e87449d1.tar.gz
bcm5719-llvm-f83d547989c2dab2353cafb4aafa3561e87449d1.zip
[analyzer] NFC: Track all constructed objects in a single state trait.
ExprEngine already maintains three internal program state traits to track path-sensitive information related to object construction: pointer returned by operator new, and pointer to temporary object for two different purposes - for destruction and for lifetime extension. We'll need to add 2-3 more in a few follow-up commits. Merge these traits into one because they all essentially serve one purpose and work similarly. Differential Revision: https://reviews.llvm.org/D47303 llvm-svn: 333719
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp67
1 files changed, 34 insertions, 33 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 90a35f39324..997ff6a5a26 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -111,11 +111,10 @@ SVal ExprEngine::makeZeroElementRegion(ProgramStateRef State, SVal LValue,
}
-const MemRegion *
-ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
- ExplodedNode *Pred,
- const ConstructionContext *CC,
- EvalCallOptions &CallOpts) {
+SVal ExprEngine::getLocationForConstructedObject(const CXXConstructExpr *CE,
+ ExplodedNode *Pred,
+ const ConstructionContext *CC,
+ EvalCallOptions &CallOpts) {
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
@@ -130,9 +129,8 @@ ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
const auto *Var = cast<VarDecl>(DS->getSingleDecl());
SVal LValue = State->getLValue(Var, LCtx);
QualType Ty = Var->getType();
- LValue =
- makeZeroElementRegion(State, LValue, Ty, CallOpts.IsArrayCtorOrDtor);
- return LValue.getAsRegion();
+ return makeZeroElementRegion(State, LValue, Ty,
+ CallOpts.IsArrayCtorOrDtor);
}
case ConstructionContext::SimpleConstructorInitializerKind: {
const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC);
@@ -156,25 +154,26 @@ ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
QualType Ty = Field->getType();
FieldVal = makeZeroElementRegion(State, FieldVal, Ty,
CallOpts.IsArrayCtorOrDtor);
- return FieldVal.getAsRegion();
+ return FieldVal;
}
case ConstructionContext::NewAllocatedObjectKind: {
if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) {
const auto *NECC = cast<NewAllocatedObjectConstructionContext>(CC);
const auto *NE = NECC->getCXXNewExpr();
- // TODO: Detect when the allocator returns a null pointer.
- // Constructor shall not be called in this case.
- if (const SubRegion *MR = dyn_cast_or_null<SubRegion>(
- getCXXNewAllocatorValue(State, NE, LCtx).getAsRegion())) {
+ SVal V = *getObjectUnderConstruction(State, NE, LCtx);
+ if (const SubRegion *MR =
+ dyn_cast_or_null<SubRegion>(V.getAsRegion())) {
if (NE->isArray()) {
// TODO: In fact, we need to call the constructor for every
// allocated element, not just the first one!
CallOpts.IsArrayCtorOrDtor = true;
- return getStoreManager().GetElementZeroRegion(
- MR, NE->getType()->getPointeeType());
+ return loc::MemRegionVal(getStoreManager().GetElementZeroRegion(
+ MR, NE->getType()->getPointeeType()));
}
- return MR;
+ return V;
}
+ // TODO: Detect when the allocator returns a null pointer.
+ // Constructor shall not be called in this case.
}
break;
}
@@ -205,7 +204,7 @@ ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
// TODO: Support temporaries lifetime-extended via static references.
// They'd need a getCXXStaticTempObjectRegion().
CallOpts.IsTemporaryCtorOrDtor = true;
- return MRMgr.getCXXTempObjectRegion(CE, LCtx);
+ return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(CE, LCtx));
}
case ConstructionContext::SimpleReturnedValueKind: {
// The temporary is to be managed by the parent stack frame.
@@ -226,7 +225,7 @@ ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
} else if (!isa<TemporaryObjectConstructionContext>(
RTC->getConstructionContext())) {
- // FXIME: The return value is constructed directly into a
+ // FIXME: The return value is constructed directly into a
// non-temporary due to C++17 mandatory copy elision. This is not
// implemented yet.
assert(getContext().getLangOpts().CPlusPlus17);
@@ -235,7 +234,7 @@ ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
TempLCtx = CallerLCtx;
}
CallOpts.IsTemporaryCtorOrDtor = true;
- return MRMgr.getCXXTempObjectRegion(CE, TempLCtx);
+ return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(CE, TempLCtx));
}
case ConstructionContext::CXX17ElidedCopyVariableKind:
case ConstructionContext::CXX17ElidedCopyReturnedValueKind:
@@ -247,7 +246,7 @@ ExprEngine::getRegionForConstructedObject(const CXXConstructExpr *CE,
// If we couldn't find an existing region to construct into, assume we're
// constructing a temporary. Notify the caller of our failure.
CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
- return MRMgr.getCXXTempObjectRegion(CE, LCtx);
+ return loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(CE, LCtx));
}
const CXXConstructExpr *
@@ -285,7 +284,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
const LocationContext *LCtx = Pred->getLocationContext();
ProgramStateRef State = Pred->getState();
- const MemRegion *Target = nullptr;
+ SVal Target = UnknownVal();
// FIXME: Handle arrays, which run the same constructor for every element.
// For now, we just run the first constructor (which should still invalidate
@@ -298,7 +297,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
switch (CE->getConstructionKind()) {
case CXXConstructExpr::CK_Complete: {
- Target = getRegionForConstructedObject(CE, Pred, CC, CallOpts);
+ Target = getLocationForConstructedObject(CE, Pred, CC, CallOpts);
break;
}
case CXXConstructExpr::CK_VirtualBase:
@@ -334,7 +333,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
// otherwise always available during construction.
if (dyn_cast_or_null<InitListExpr>(LCtx->getParentMap().getParent(CE))) {
MemRegionManager &MRMgr = getSValBuilder().getRegionManager();
- Target = MRMgr.getCXXTempObjectRegion(CE, LCtx);
+ Target = loc::MemRegionVal(MRMgr.getCXXTempObjectRegion(CE, LCtx));
CallOpts.IsCtorOrDtorWithImproperlyModeledTargetRegion = true;
break;
}
@@ -346,14 +345,14 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
SVal ThisVal = State->getSVal(ThisPtr);
if (CE->getConstructionKind() == CXXConstructExpr::CK_Delegating) {
- Target = ThisVal.getAsRegion();
+ Target = ThisVal;
} else {
// Cast to the base type.
bool IsVirtual =
(CE->getConstructionKind() == CXXConstructExpr::CK_VirtualBase);
SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, CE->getType(),
IsVirtual);
- Target = BaseVal.getAsRegion();
+ Target = BaseVal;
}
break;
}
@@ -361,7 +360,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
CallEventManager &CEMgr = getStateManager().getCallEventManager();
CallEventRef<CXXConstructorCall> Call =
- CEMgr.getCXXConstructorCall(CE, Target, State, LCtx);
+ CEMgr.getCXXConstructorCall(CE, Target.getAsRegion(), State, LCtx);
ExplodedNodeSet DstPreVisit;
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this);
@@ -387,10 +386,11 @@ 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->bindDefaultZero(loc::MemRegionVal(Target), LCtx);
+ State = State->bindDefaultZero(Target, LCtx);
}
- State = addAllNecessaryTemporaryInfo(State, CC, LCtx, Target);
+ State = markStatementsCorrespondingToConstructedObject(State, CC, LCtx,
+ Target);
Bldr.generateNode(CE, *I, State, /*tag=*/nullptr,
ProgramPoint::PreStmtKind);
@@ -550,8 +550,8 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
State = State->assume(RetVal.castAs<DefinedOrUnknownSVal>(), true);
}
- ValueBldr.generateNode(CNE, I,
- setCXXNewAllocatorValue(State, CNE, LCtx, RetVal));
+ ValueBldr.generateNode(
+ CNE, I, addObjectUnderConstruction(State, CNE, LCtx, RetVal));
}
ExplodedNodeSet DstPostPostCallCallback;
@@ -559,7 +559,8 @@ void ExprEngine::VisitCXXNewAllocatorCall(const CXXNewExpr *CNE,
DstPostValue, *Call, *this);
for (auto I : DstPostPostCallCallback) {
getCheckerManager().runCheckersForNewAllocator(
- CNE, getCXXNewAllocatorValue(I->getState(), CNE, LCtx), Dst, I, *this);
+ CNE, *getObjectUnderConstruction(I->getState(), CNE, LCtx), Dst, I,
+ *this);
}
}
@@ -582,8 +583,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
// Retrieve the stored operator new() return value.
if (AMgr.getAnalyzerOptions().mayInlineCXXAllocator()) {
- symVal = getCXXNewAllocatorValue(State, CNE, LCtx);
- State = clearCXXNewAllocatorValue(State, CNE, LCtx);
+ symVal = *getObjectUnderConstruction(State, CNE, LCtx);
+ State = finishObjectConstruction(State, CNE, LCtx);
}
// We assume all standard global 'operator new' functions allocate memory in
OpenPOWER on IntegriCloud