[clang] 8f68022 - [clang][analyzer] Fix crash in loop unrolling (#82089)

via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 14 01:16:44 PDT 2024


Author: huang-me
Date: 2024-03-14T09:16:40+01:00
New Revision: 8f68022f8e6e54d1aeae4ed301f5a015963089b7

URL: https://github.com/llvm/llvm-project/commit/8f68022f8e6e54d1aeae4ed301f5a015963089b7
DIFF: https://github.com/llvm/llvm-project/commit/8f68022f8e6e54d1aeae4ed301f5a015963089b7.diff

LOG: [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 <benicsbalazs at gmail.com>

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
    clang/test/Analysis/loop-unrolling.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index abeb5a8b77bf1f..71c1edc8f67b17 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -492,6 +492,10 @@ libclang
 Static Analyzer
 ---------------
 
+- Fixed crashing on loops if the loop variable was declared in switch blocks
+  but not under any case blocks if ``unroll-loops=true`` analyzer config is
+  set. (#GH68819)
+
 New features
 ^^^^^^^^^^^^
 

diff  --git a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
index a80352816be613..7042f1aeb803fc 100644
--- a/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ b/clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -190,6 +190,17 @@ static bool isCapturedByReference(ExplodedNode *N, const DeclRefExpr *DR) {
   return FD->getType()->isReferenceType();
 }
 
+static bool isFoundInStmt(const Stmt *S, const VarDecl *VD) {
+  if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
+    for (const Decl *D : DS->decls()) {
+      // Once we reach the declaration of the VD we can return.
+      if (D->getCanonicalDecl() == VD)
+        return true;
+    }
+  }
+  return false;
+}
+
 // A loop counter is considered escaped if:
 // case 1: It is a global variable.
 // case 2: It is a reference parameter or a reference capture.
@@ -219,13 +230,19 @@ static bool isPossiblyEscaped(ExplodedNode *N, const DeclRefExpr *DR) {
       continue;
     }
 
-    if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) {
-      for (const Decl *D : DS->decls()) {
-        // Once we reach the declaration of the VD we can return.
-        if (D->getCanonicalDecl() == VD)
-          return false;
+    if (isFoundInStmt(S, VD)) {
+      return false;
+    }
+
+    if (const auto *SS = dyn_cast<SwitchStmt>(S)) {
+      if (const auto *CST = dyn_cast<CompoundStmt>(SS->getBody())) {
+        for (const Stmt *CB : CST->body()) {
+          if (isFoundInStmt(CB, VD))
+            return false;
+        }
       }
     }
+
     // Check the usage of the pass-by-ref function calls and adress-of operator
     // on VD and reference initialized by VD.
     ASTContext &ASTCtx =

diff  --git a/clang/test/Analysis/loop-unrolling.cpp b/clang/test/Analysis/loop-unrolling.cpp
index fc1fb06cdc014e..66a828abfb5133 100644
--- a/clang/test/Analysis/loop-unrolling.cpp
+++ b/clang/test/Analysis/loop-unrolling.cpp
@@ -547,3 +547,15 @@ void capture_implicitly_by_ref_as_loop_counter() {
     }
   };
 }
+
+
+void test_escaping_on_var_before_switch_case_no_crash(int c) {
+  // https://github.com/llvm/llvm-project/issues/68819
+  switch (c) {
+    int i; // no-crash: The declaration of `i` is found here.
+    case 0: {
+      for (i = 0; i < 16; i++) {}
+      break;
+    }
+  }
+}


        


More information about the cfe-commits mailing list