Skip to content

Commit 8f68022

Browse files
huang-mesteakhal
andauthored
[clang][analyzer] Fix crash in loop unrolling (#82089)
StaticAnalyzer didn't check if the variable is declared in `CompoundStmt` under `SwitchStmt`, which make static analyzer reach root without finding the declaration. Fixes #68819 --------- Co-authored-by: Balazs Benics <[email protected]>
1 parent 2582965 commit 8f68022

File tree

3 files changed

+38
-5
lines changed

3 files changed

+38
-5
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,10 @@ libclang
492492
Static Analyzer
493493
---------------
494494

495+
- Fixed crashing on loops if the loop variable was declared in switch blocks
496+
but not under any case blocks if ``unroll-loops=true`` analyzer config is
497+
set. (#GH68819)
498+
495499
New features
496500
^^^^^^^^^^^^
497501

clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,17 @@ static bool isCapturedByReference(ExplodedNode *N, const DeclRefExpr *DR) {
190190
return FD->getType()->isReferenceType();
191191
}
192192

193+
static bool isFoundInStmt(const Stmt *S, const VarDecl *VD) {
194+
if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
195+
for (const Decl *D : DS->decls()) {
196+
// Once we reach the declaration of the VD we can return.
197+
if (D->getCanonicalDecl() == VD)
198+
return true;
199+
}
200+
}
201+
return false;
202+
}
203+
193204
// A loop counter is considered escaped if:
194205
// case 1: It is a global variable.
195206
// case 2: It is a reference parameter or a reference capture.
@@ -219,13 +230,19 @@ static bool isPossiblyEscaped(ExplodedNode *N, const DeclRefExpr *DR) {
219230
continue;
220231
}
221232

222-
if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
223-
for (const Decl *D : DS->decls()) {
224-
// Once we reach the declaration of the VD we can return.
225-
if (D->getCanonicalDecl() == VD)
226-
return false;
233+
if (isFoundInStmt(S, VD)) {
234+
return false;
235+
}
236+
237+
if (const auto *SS = dyn_cast<SwitchStmt>(S)) {
238+
if (const auto *CST = dyn_cast<CompoundStmt>(SS->getBody())) {
239+
for (const Stmt *CB : CST->body()) {
240+
if (isFoundInStmt(CB, VD))
241+
return false;
242+
}
227243
}
228244
}
245+
229246
// Check the usage of the pass-by-ref function calls and adress-of operator
230247
// on VD and reference initialized by VD.
231248
ASTContext &ASTCtx =

clang/test/Analysis/loop-unrolling.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -547,3 +547,15 @@ void capture_implicitly_by_ref_as_loop_counter() {
547547
}
548548
};
549549
}
550+
551+
552+
void test_escaping_on_var_before_switch_case_no_crash(int c) {
553+
// https://github.com/llvm/llvm-project/issues/68819
554+
switch (c) {
555+
int i; // no-crash: The declaration of `i` is found here.
556+
case 0: {
557+
for (i = 0; i < 16; i++) {}
558+
break;
559+
}
560+
}
561+
}

0 commit comments

Comments
 (0)