Skip to content

Commit a5fbcd5

Browse files
committed
[analyzer] Fix a crash from element region construction during ArrayInitLoopExpr analysis
This patch generalizes the way element regions are constructed when an `ArrayInitLoopExpr` is being analyzed. Previously the base region of the `ElementRegion` was determined with pattern matching, which led to crashes, when an unhandled pattern was encountered. Fixes llvm#112813
1 parent cd0373e commit a5fbcd5

File tree

2 files changed

+56
-57
lines changed

2 files changed

+56
-57
lines changed

clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp

+12-57
Original file line numberDiff line numberDiff line change
@@ -513,70 +513,25 @@ ProgramStateRef ExprEngine::updateObjectsUnderConstruction(
513513
static ProgramStateRef
514514
bindRequiredArrayElementToEnvironment(ProgramStateRef State,
515515
const ArrayInitLoopExpr *AILE,
516-
const LocationContext *LCtx, SVal Idx) {
517-
// The ctor in this case is guaranteed to be a copy ctor, otherwise we hit a
518-
// compile time error.
519-
//
520-
// -ArrayInitLoopExpr <-- we're here
521-
// |-OpaqueValueExpr
522-
// | `-DeclRefExpr <-- match this
523-
// `-CXXConstructExpr
524-
// `-ImplicitCastExpr
525-
// `-ArraySubscriptExpr
526-
// |-ImplicitCastExpr
527-
// | `-OpaqueValueExpr
528-
// | `-DeclRefExpr
529-
// `-ArrayInitIndexExpr
530-
//
531-
// The resulting expression might look like the one below in an implicit
532-
// copy/move ctor.
533-
//
534-
// ArrayInitLoopExpr <-- we're here
535-
// |-OpaqueValueExpr
536-
// | `-MemberExpr <-- match this
537-
// | (`-CXXStaticCastExpr) <-- move ctor only
538-
// | `-DeclRefExpr
539-
// `-CXXConstructExpr
540-
// `-ArraySubscriptExpr
541-
// |-ImplicitCastExpr
542-
// | `-OpaqueValueExpr
543-
// | `-MemberExpr
544-
// | `-DeclRefExpr
545-
// `-ArrayInitIndexExpr
546-
//
547-
// The resulting expression for a multidimensional array.
548-
// ArrayInitLoopExpr <-- we're here
549-
// |-OpaqueValueExpr
550-
// | `-DeclRefExpr <-- match this
551-
// `-ArrayInitLoopExpr
552-
// |-OpaqueValueExpr
553-
// | `-ArraySubscriptExpr
554-
// | |-ImplicitCastExpr
555-
// | | `-OpaqueValueExpr
556-
// | | `-DeclRefExpr
557-
// | `-ArrayInitIndexExpr
558-
// `-CXXConstructExpr <-- extract this
559-
// ` ...
560-
561-
const auto *OVESrc = AILE->getCommonExpr()->getSourceExpr();
516+
const LocationContext *LCtx, NonLoc Idx) {
517+
SValBuilder &SVB = State->getStateManager().getSValBuilder();
518+
MemRegionManager &MRMgr = SVB.getRegionManager();
519+
ASTContext &Ctx = SVB.getContext();
562520

563521
// HACK: There is no way we can put the index of the array element into the
564522
// CFG unless we unroll the loop, so we manually select and bind the required
565523
// parameter to the environment.
566-
const auto *CE =
524+
const Expr *SourceArray = AILE->getCommonExpr()->getSourceExpr();
525+
const auto *Ctor =
567526
cast<CXXConstructExpr>(extractElementInitializerFromNestedAILE(AILE));
568527

569-
SVal Base = UnknownVal();
570-
if (const auto *ME = dyn_cast<MemberExpr>(OVESrc))
571-
Base = State->getSVal(ME, LCtx);
572-
else if (const auto *DRE = dyn_cast<DeclRefExpr>(OVESrc))
573-
Base = State->getLValue(cast<VarDecl>(DRE->getDecl()), LCtx);
574-
else
575-
llvm_unreachable("ArrayInitLoopExpr contains unexpected source expression");
576-
577-
SVal NthElem = State->getLValue(CE->getType(), Idx, Base);
528+
const SubRegion *SourceArrayRegion =
529+
cast<SubRegion>(State->getSVal(SourceArray, LCtx).getAsRegion());
530+
const ElementRegion *ElementRegion =
531+
MRMgr.getElementRegion(Ctor->getType(), Idx, SourceArrayRegion, Ctx);
578532

579-
return State->BindExpr(CE->getArg(0), LCtx, NthElem);
533+
return State->BindExpr(Ctor->getArg(0), LCtx,
534+
loc::MemRegionVal(ElementRegion));
580535
}
581536

582537
void ExprEngine::handleConstructor(const Expr *E,

clang/test/Analysis/array-init-loop.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,47 @@ void no_crash() {
330330
}
331331

332332
} // namespace crash
333+
334+
namespace array_subscript_initializer {
335+
336+
struct S
337+
{
338+
int x;
339+
};
340+
341+
void no_crash() {
342+
S arr[][2] = {{1, 2}};
343+
344+
const auto [a, b] = arr[0];
345+
346+
clang_analyzer_eval(a.x == 1); // expected-warning{{TRUE}}
347+
clang_analyzer_eval(b.x == 2); // expected-warning{{TRUE}}
348+
}
349+
350+
} // namespace array_subscript_initializer
351+
352+
namespace iterator_initializer {
353+
354+
struct S
355+
{
356+
int x;
357+
};
358+
359+
void no_crash() {
360+
S arr[][2] = {{1, 2}, {3, 4}};
361+
362+
int i = 0;
363+
for (const auto [a, b] : arr) {
364+
if (i == 0) {
365+
clang_analyzer_eval(a.x == 1); // expected-warning{{TRUE}}
366+
clang_analyzer_eval(b.x == 2); // expected-warning{{TRUE}}
367+
} else {
368+
clang_analyzer_eval(a.x == 3); // expected-warning{{TRUE}}
369+
clang_analyzer_eval(b.x == 4); // expected-warning{{TRUE}}
370+
}
371+
372+
++i;
373+
}
374+
}
375+
376+
} // namespace iterator_initializer

0 commit comments

Comments
 (0)