-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[analyzer] Fix a crash from element region construction during ArrayInitLoopExpr analysis
#113570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-clang Author: None (isuckatcs) ChangesThis patch generalizes the way element regions are constructed when an Fixes #112813 Full diff: https://github.com/llvm/llvm-project/pull/113570.diff 2 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index c50db1e0e2f863..6ddb9b44ddcf91 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 SubRegion *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..64b0aec1daf9d2 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];
+
+ 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) {
+ clang_analyzer_eval(a.x == (i == 0 ? 1 : 3)); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.x == (i == 0 ? 2 : 4)); // expected-warning{{TRUE}}
+ ++i;
+ }
+}
+
+} // namespace iterator_initializer
\ No newline at end of file
|
|
@llvm/pr-subscribers-clang-static-analyzer-1 Author: None (isuckatcs) ChangesThis patch generalizes the way element regions are constructed when an Fixes #112813 Full diff: https://github.com/llvm/llvm-project/pull/113570.diff 2 Files Affected:
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp
index c50db1e0e2f863..6ddb9b44ddcf91 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 SubRegion *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..64b0aec1daf9d2 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];
+
+ 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) {
+ clang_analyzer_eval(a.x == (i == 0 ? 1 : 3)); // expected-warning{{TRUE}}
+ clang_analyzer_eval(b.x == (i == 0 ? 2 : 4)); // expected-warning{{TRUE}}
+ ++i;
+ }
+}
+
+} // namespace iterator_initializer
\ No newline at end of file
|
|
|
NagyDonat
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for fixing this crash!
I also happy to see that you simplify the logic and clean up the variable names. (I was a bit curious about the original reason that led to introduce this pattern matching, but I see that you're the original author of this code so I presume that you understand its role.)
I don't remember why I did it with pattern matching. I guess, I wasn't aware that |
steakhal
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add no-crash comment in the test code where we would have crashed?
Other than this, this looks good to me.
Thabks for the prompt fix!
steakhal
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still looks good.
I couldnt find the "no-crash" comments in the tests at the statements where they crashed but im fine without them too.
| void no_crash() { | ||
| S arr[][2] = {{1, 2}}; | ||
|
|
||
| const auto [a, b] = arr[0]; // no-crash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@steakhal // no-crash at the end of the line. Similarly in the other test case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad. Im too tired now.
…InitLoopExpr` 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
|
@steakhal I wanted to wait for the pipeline to pass before merging. Shouldn't we only merge patches with a green pipeline? |
The full pipeline will never be green. Downstream I wouldn't do this, but here I think we did what is reasonable. Waited enough. We can always revert with a single push of a button. |
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/73/builds/7599 Here is the relevant piece of the build log for the reference |
…InitLoopExpr` analysis (llvm#113570) 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
This patch generalizes the way element regions are constructed when an
ArrayInitLoopExpris being analyzed. Previously the base region of theElementRegionwas determined with pattern matching, which led to crashes, when an unhandled pattern was encountered.Fixes #112813