[clang] [analyzer] Fix a crash from element region construction during `ArrayInitLoopExpr` analysis (PR #113570)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Oct 25 10:25:27 PDT 2024
https://github.com/isuckatcs updated https://github.com/llvm/llvm-project/pull/113570
>From dfb862d8a9e2614a35d846f54eb5f4f2d83ddfa2 Mon Sep 17 00:00:00 2001
From: isuckatcs <65320245+isuckatcs at users.noreply.github.com>
Date: Thu, 24 Oct 2024 16:01:42 +0200
Subject: [PATCH] [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 #112813
---
.../lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 69 ++++---------------
clang/test/Analysis/array-init-loop.cpp | 38 ++++++++++
2 files changed, 50 insertions(+), 57 deletions(-)
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index c50db1e0e2f863..ccc3097e8d2f97 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
@@ -513,70 +513,25 @@ ProgramStateRef ExprEngine::updateObjectsUnderConstruction(
static ProgramStateRef
bindRequiredArrayElementToEnvironment(ProgramStateRef State,
const ArrayInitLoopExpr *AILE,
- const LocationContext *LCtx, SVal Idx) {
- // The ctor in this case is guaranteed to be a copy ctor, otherwise we hit a
- // compile time error.
- //
- // -ArrayInitLoopExpr <-- we're here
- // |-OpaqueValueExpr
- // | `-DeclRefExpr <-- match this
- // `-CXXConstructExpr
- // `-ImplicitCastExpr
- // `-ArraySubscriptExpr
- // |-ImplicitCastExpr
- // | `-OpaqueValueExpr
- // | `-DeclRefExpr
- // `-ArrayInitIndexExpr
- //
- // The resulting expression might look like the one below in an implicit
- // copy/move ctor.
- //
- // ArrayInitLoopExpr <-- we're here
- // |-OpaqueValueExpr
- // | `-MemberExpr <-- match this
- // | (`-CXXStaticCastExpr) <-- move ctor only
- // | `-DeclRefExpr
- // `-CXXConstructExpr
- // `-ArraySubscriptExpr
- // |-ImplicitCastExpr
- // | `-OpaqueValueExpr
- // | `-MemberExpr
- // | `-DeclRefExpr
- // `-ArrayInitIndexExpr
- //
- // The resulting expression for a multidimensional array.
- // ArrayInitLoopExpr <-- we're here
- // |-OpaqueValueExpr
- // | `-DeclRefExpr <-- match this
- // `-ArrayInitLoopExpr
- // |-OpaqueValueExpr
- // | `-ArraySubscriptExpr
- // | |-ImplicitCastExpr
- // | | `-OpaqueValueExpr
- // | | `-DeclRefExpr
- // | `-ArrayInitIndexExpr
- // `-CXXConstructExpr <-- extract this
- // ` ...
-
- const auto *OVESrc = AILE->getCommonExpr()->getSourceExpr();
+ const LocationContext *LCtx, NonLoc Idx) {
+ SValBuilder &SVB = State->getStateManager().getSValBuilder();
+ MemRegionManager &MRMgr = SVB.getRegionManager();
+ ASTContext &Ctx = SVB.getContext();
// HACK: There is no way we can put the index of the array element into the
// CFG unless we unroll the loop, so we manually select and bind the required
// parameter to the environment.
- const auto *CE =
+ const Expr *SourceArray = AILE->getCommonExpr()->getSourceExpr();
+ const auto *Ctor =
cast<CXXConstructExpr>(extractElementInitializerFromNestedAILE(AILE));
- SVal Base = UnknownVal();
- if (const auto *ME = dyn_cast<MemberExpr>(OVESrc))
- Base = State->getSVal(ME, LCtx);
- else if (const auto *DRE = dyn_cast<DeclRefExpr>(OVESrc))
- Base = State->getLValue(cast<VarDecl>(DRE->getDecl()), LCtx);
- else
- llvm_unreachable("ArrayInitLoopExpr contains unexpected source expression");
-
- SVal NthElem = State->getLValue(CE->getType(), Idx, Base);
+ const auto *SourceArrayRegion =
+ cast<SubRegion>(State->getSVal(SourceArray, LCtx).getAsRegion());
+ const ElementRegion *ElementRegion =
+ MRMgr.getElementRegion(Ctor->getType(), Idx, SourceArrayRegion, Ctx);
- return State->BindExpr(CE->getArg(0), LCtx, NthElem);
+ return State->BindExpr(Ctor->getArg(0), LCtx,
+ loc::MemRegionVal(ElementRegion));
}
void ExprEngine::handleConstructor(const Expr *E,
diff --git a/clang/test/Analysis/array-init-loop.cpp b/clang/test/Analysis/array-init-loop.cpp
index 4ab4489fc882f3..b28468b7f560b2 100644
--- a/clang/test/Analysis/array-init-loop.cpp
+++ b/clang/test/Analysis/array-init-loop.cpp
@@ -330,3 +330,41 @@ void no_crash() {
}
} // namespace crash
+
+namespace array_subscript_initializer {
+struct S {
+ int x;
+};
+
+void no_crash() {
+ S arr[][2] = {{1, 2}};
+
+ const auto [a, b] = arr[0]; // no-crash
+
+ clang_analyzer_eval(a.x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.x == 2); // expected-warning{{TRUE}}
+}
+} // namespace array_subscript_initializer
+
+namespace iterator_initializer {
+struct S {
+ int x;
+};
+
+void no_crash() {
+ S arr[][2] = {{1, 2}, {3, 4}};
+
+ int i = 0;
+ for (const auto [a, b] : arr) { // no-crash
+ if (i == 0) {
+ clang_analyzer_eval(a.x == 1); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.x == 2); // expected-warning{{TRUE}}
+ } else {
+ clang_analyzer_eval(a.x == 3); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.x == 4); // expected-warning{{TRUE}}
+ }
+
+ ++i;
+ }
+}
+} // namespace iterator_initializer
More information about the cfe-commits
mailing list