Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -438,6 +438,10 @@ /// other functions that handle specific kinds of statements. void Visit(const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); + /// VisitArrayInitLoopExpr - Transfer function for array init loop. + void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex, ExplodedNode *Pred, + ExplodedNodeSet &Dst); + /// VisitArraySubscriptExpr - Transfer function for array accesses. void VisitArraySubscriptExpr(const ArraySubscriptExpr *Ex, ExplodedNode *Pred, Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1375,10 +1375,14 @@ break; } + case Stmt::ArrayInitLoopExprClass: + Bldr.takeNodes(Pred); + VisitArrayInitLoopExpr(cast(S), Pred, Dst); + Bldr.addNodes(Dst); + break; // Cases not handled yet; but will handle some day. case Stmt::DesignatedInitExprClass: case Stmt::DesignatedInitUpdateExprClass: - case Stmt::ArrayInitLoopExprClass: case Stmt::ArrayInitIndexExprClass: case Stmt::ExtVectorElementExprClass: case Stmt::ImaginaryLiteralClass: @@ -2622,6 +2626,64 @@ llvm_unreachable("Support for this Decl not implemented."); } +/// VisitArrayInitLoopExpr - Transfer function for array init loop. +void ExprEngine::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *Ex, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + + const OpaqueValueExpr *Arr = Ex->getCommonExpr(); + const Expr *Init = Ex->getSubExpr(); + + std::size_t ArrSize = 0; + llvm::APInt ASI = Ex->getArraySize(); + while (ASI != 0) { + ++ArrSize; + --ASI; + } + + ExplodedNodeSet CheckerPreStmt; + getCheckerManager().runCheckersForPreStmt(CheckerPreStmt, Pred, Ex, *this); + + ExplodedNodeSet EvalSet; + StmtNodeBuilder Bldr(CheckerPreStmt, EvalSet, *currBldrCtx); + + for (auto *Node : CheckerPreStmt) { + const LocationContext *LCtx = Node->getLocationContext(); + ProgramStateRef state = Node->getState(); + + llvm::ImmutableList vals = getBasicVals().getEmptySValList(); + + const DeclRefExpr *DRE = dyn_cast(Arr->getSourceExpr()); + SVal Base = state->getLValue(cast(DRE->getDecl()), LCtx); + state = state->BindExpr(DRE, LCtx, Base); + + for (std::size_t i = ArrSize; i != 0; --i) { + + SVal V = + state->getLValue(Init->getType(), svalBuilder.makeArrayIndex(i - 1), + state->getSVal(Arr->getSourceExpr(), LCtx)); + + // store the value of the element, not the reference to it, to avoid false + // results eg.: + // int arr[2]; + // auto[a, b] = arr; + // arr[0] = 0; + // a; <-- this needs to be Undefined, not 0 + if (const MemRegion *R = V.getAsRegion()) + V = state->getSVal(R); + + vals = getBasicVals().prependSVal(V, vals); + } + + Bldr.generateNode( + Ex, Pred, + state->BindExpr(Ex, LCtx, + svalBuilder.makeCompoundVal(Ex->getType(), vals))); + } + + getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); +} + /// VisitArraySubscriptExpr - Transfer function for array accesses void ExprEngine::VisitArraySubscriptExpr(const ArraySubscriptExpr *A, ExplodedNode *Pred,