aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp77
1 files changed, 55 insertions, 22 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index 6d979da2755f..08fac9fb2e69 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -94,15 +94,17 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred,
}
}
-
-SVal ExprEngine::makeZeroElementRegion(ProgramStateRef State, SVal LValue,
- QualType &Ty, bool &IsArray) {
+SVal ExprEngine::makeElementRegion(ProgramStateRef State, SVal LValue,
+ QualType &Ty, bool &IsArray, unsigned Idx) {
SValBuilder &SVB = State->getStateManager().getSValBuilder();
ASTContext &Ctx = SVB.getContext();
- while (const ArrayType *AT = Ctx.getAsArrayType(Ty)) {
- Ty = AT->getElementType();
- LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue);
+ if (const ArrayType *AT = Ctx.getAsArrayType(Ty)) {
+ while (AT) {
+ Ty = AT->getElementType();
+ AT = dyn_cast<ArrayType>(AT->getElementType());
+ }
+ LValue = State->getLValue(Ty, SVB.makeArrayIndex(Idx), LValue);
IsArray = true;
}
@@ -111,7 +113,7 @@ SVal ExprEngine::makeZeroElementRegion(ProgramStateRef State, SVal LValue,
SVal ExprEngine::computeObjectUnderConstruction(
const Expr *E, ProgramStateRef State, const LocationContext *LCtx,
- const ConstructionContext *CC, EvalCallOptions &CallOpts) {
+ const ConstructionContext *CC, EvalCallOptions &CallOpts, unsigned Idx) {
SValBuilder &SVB = getSValBuilder();
MemRegionManager &MRMgr = SVB.getRegionManager();
ASTContext &ACtx = SVB.getContext();
@@ -125,8 +127,8 @@ SVal ExprEngine::computeObjectUnderConstruction(
const auto *DS = DSCC->getDeclStmt();
const auto *Var = cast<VarDecl>(DS->getSingleDecl());
QualType Ty = Var->getType();
- return makeZeroElementRegion(State, State->getLValue(Var, LCtx), Ty,
- CallOpts.IsArrayCtorOrDtor);
+ return makeElementRegion(State, State->getLValue(Var, LCtx), Ty,
+ CallOpts.IsArrayCtorOrDtor, Idx);
}
case ConstructionContext::CXX17ElidedCopyConstructorInitializerKind:
case ConstructionContext::SimpleConstructorInitializerKind: {
@@ -158,8 +160,8 @@ SVal ExprEngine::computeObjectUnderConstruction(
}
QualType Ty = Field->getType();
- return makeZeroElementRegion(State, FieldVal, Ty,
- CallOpts.IsArrayCtorOrDtor);
+ return makeElementRegion(State, FieldVal, Ty, CallOpts.IsArrayCtorOrDtor,
+ Idx);
}
case ConstructionContext::NewAllocatedObjectKind: {
if (AMgr.getAnalyzerOptions().MayInlineCXXAllocator) {
@@ -172,8 +174,12 @@ SVal ExprEngine::computeObjectUnderConstruction(
// TODO: In fact, we need to call the constructor for every
// allocated element, not just the first one!
CallOpts.IsArrayCtorOrDtor = true;
- return loc::MemRegionVal(getStoreManager().GetElementZeroRegion(
- MR, NE->getType()->getPointeeType()));
+
+ auto R = MRMgr.getElementRegion(NE->getType()->getPointeeType(),
+ svalBuilder.makeArrayIndex(Idx), MR,
+ SVB.getContext());
+
+ return loc::MemRegionVal(R);
}
return V;
}
@@ -484,10 +490,6 @@ void ExprEngine::handleConstructor(const Expr *E,
}
}
- // FIXME: Handle arrays, which run the same constructor for every element.
- // For now, we just run the first constructor (which should still invalidate
- // the entire array).
-
EvalCallOptions CallOpts;
auto C = getCurrentCFGElement().getAs<CFGConstructor>();
assert(C || getCurrentCFGElement().getAs<CFGStmt>());
@@ -500,9 +502,15 @@ void ExprEngine::handleConstructor(const Expr *E,
// Inherited constructors are always base class constructors.
assert(CE && !CIE && "A complete constructor is inherited?!");
+ unsigned Idx = 0;
+ if (CE->getType()->isArrayType()) {
+ Idx = getIndexOfElementToConstruct(State, CE, LCtx).value_or(0u);
+ State = setIndexOfElementToConstruct(State, CE, LCtx, Idx + 1);
+ }
+
// The target region is found from construction context.
std::tie(State, Target) =
- handleConstructionContext(CE, State, LCtx, CC, CallOpts);
+ handleConstructionContext(CE, State, LCtx, CC, CallOpts, Idx);
break;
}
case CXXConstructExpr::CK_VirtualBase: {
@@ -894,14 +902,39 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
SVal Result = symVal;
if (CNE->isArray()) {
- // FIXME: allocating an array requires simulating the constructors.
- // For now, just return a symbolicated region.
+
if (const auto *NewReg = cast_or_null<SubRegion>(symVal.getAsRegion())) {
- QualType ObjTy = CNE->getType()->getPointeeType();
+ // If each element is initialized by their default constructor, the field
+ // values are properly placed inside the required region, however if an
+ // initializer list is used, this doesn't happen automatically.
+ auto *Init = CNE->getInitializer();
+ bool isInitList = dyn_cast_or_null<InitListExpr>(Init);
+
+ QualType ObjTy =
+ isInitList ? Init->getType() : CNE->getType()->getPointeeType();
const ElementRegion *EleReg =
- getStoreManager().GetElementZeroRegion(NewReg, ObjTy);
+ MRMgr.getElementRegion(ObjTy, svalBuilder.makeArrayIndex(0), NewReg,
+ svalBuilder.getContext());
Result = loc::MemRegionVal(EleReg);
+
+ // If the array is list initialized, we bind the initializer list to the
+ // memory region here, otherwise we would lose it.
+ if (isInitList) {
+ Bldr.takeNodes(Pred);
+ Pred = Bldr.generateNode(CNE, Pred, State);
+
+ SVal V = State->getSVal(Init, LCtx);
+ ExplodedNodeSet evaluated;
+ evalBind(evaluated, CNE, Pred, Result, V, true);
+
+ Bldr.takeNodes(Pred);
+ Bldr.addNodes(evaluated);
+
+ Pred = *evaluated.begin();
+ State = Pred->getState();
+ }
}
+
State = State->BindExpr(CNE, Pred->getLocationContext(), Result);
Bldr.generateNode(CNE, Pred, State);
return;