diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
| -rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 77 |
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; |
