[clang] [clang][Static analyzer] fix crash on using `bitcast(<type>, <array>)` as array subscript (PR #101647)

Pavel Skripkin via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 2 07:06:41 PDT 2024


https://github.com/pskrgag updated https://github.com/llvm/llvm-project/pull/101647

>From d94748f76ca793bf40cb57dd904d487c51bdcd40 Mon Sep 17 00:00:00 2001
From: Pavel Skripkin <paskripkin at gmail.com>
Date: Fri, 2 Aug 2024 12:02:11 +0300
Subject: [PATCH 1/4] clang/csa: fix crash on using bitcast(<type>, <array>) as
 array subscript

---
 clang/lib/StaticAnalyzer/Core/Store.cpp | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp
index 67ca61bb56ba2..72587ef31a17c 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -472,7 +472,19 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
   const auto *ElemR = dyn_cast<ElementRegion>(BaseRegion);
 
   // Convert the offset to the appropriate size and signedness.
-  Offset = svalBuilder.convertToArrayIndex(Offset).castAs<NonLoc>();
+  auto Off = svalBuilder.convertToArrayIndex(Offset).getAs<NonLoc>();
+  if (!Off) {
+    // Handle cases when LazyCompoundVal is used for an array index.
+    // Such case is possible if code does:
+    //
+    //   char b[4];
+    //   a[__builtin_bitcast(int, b)];
+    //
+    // Return UnknownVal, since we cannot model it.
+    return UnknownVal();
+  }
+
+  Offset = Off.value();
 
   if (!ElemR) {
     // If the base region is not an ElementRegion, create one.

>From 515520dde7eb4d0365b0eed4627b19d4dedde5d7 Mon Sep 17 00:00:00 2001
From: Pavel Skripkin <paskripkin at gmail.com>
Date: Fri, 2 Aug 2024 12:14:11 +0300
Subject: [PATCH 2/4] clang/csa: add test case for array[bitcast(<type>,
 <array>)]

---
 clang/test/Analysis/exercise-ps.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/clang/test/Analysis/exercise-ps.c b/clang/test/Analysis/exercise-ps.c
index d1e1771afddb5..9bba16c282967 100644
--- a/clang/test/Analysis/exercise-ps.c
+++ b/clang/test/Analysis/exercise-ps.c
@@ -30,3 +30,10 @@ void f3(void *dest) {
   void *src = __builtin_alloca(5);
   memcpy(dest, src, 1); // expected-warning{{2nd function call argument is a pointer to uninitialized value}}
 }
+
+// Reproduce crash from GH#94496. When array is used as subcript to another array, CSA cannot model it
+// and should just assume it's unknown and do not crash.
+void f4(char *array) {
+  char b[4] = {0};
+  array[__builtin_bit_cast(int, b)] = 0x10; // no crash
+}

>From 514d89e411285451625a4adad55eedea0e850cdc Mon Sep 17 00:00:00 2001
From: Pavel Skripkin <paskripkin at gmail.com>
Date: Fri, 2 Aug 2024 13:56:10 +0300
Subject: [PATCH 3/4] clang/csa: pin triple with sizeof(int) == 4 in
 exercise-ps and fix style

---
 clang/lib/StaticAnalyzer/Core/Store.cpp | 2 --
 clang/test/Analysis/exercise-ps.c       | 8 ++++++--
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp
index 72587ef31a17c..b436dd746d21f 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -476,10 +476,8 @@ SVal StoreManager::getLValueElement(QualType elementType, NonLoc Offset,
   if (!Off) {
     // Handle cases when LazyCompoundVal is used for an array index.
     // Such case is possible if code does:
-    //
     //   char b[4];
     //   a[__builtin_bitcast(int, b)];
-    //
     // Return UnknownVal, since we cannot model it.
     return UnknownVal();
   }
diff --git a/clang/test/Analysis/exercise-ps.c b/clang/test/Analysis/exercise-ps.c
index 9bba16c282967..4b483b1a88a2f 100644
--- a/clang/test/Analysis/exercise-ps.c
+++ b/clang/test/Analysis/exercise-ps.c
@@ -1,5 +1,6 @@
-// RUN: %clang_analyze_cc1 %s -verify -Wno-error=implicit-function-declaration \
-// RUN:   -analyzer-checker=core,unix.Malloc \
+// RUN: %clang_analyze_cc1 %s -triple=x86_64-unknown-linux \
+// RUN:   -verify -Wno-error=implicit-function-declaration \
+// RUN:   -analyzer-checker=core,unix.Malloc,debug.ExprInspection \
 // RUN:   -analyzer-config core.CallAndMessage:ArgPointeeInitializedness=true
 //
 // Just exercise the analyzer on code that has at one point caused issues
@@ -35,5 +36,8 @@ void f3(void *dest) {
 // and should just assume it's unknown and do not crash.
 void f4(char *array) {
   char b[4] = {0};
+
+  _Static_assert(sizeof(int) == 4, "Wrong triple for the test");
+
   array[__builtin_bit_cast(int, b)] = 0x10; // no crash
 }

>From b928d7b0d2272cd022bddb0ae8b8304b3e3b8d2b Mon Sep 17 00:00:00 2001
From: Pavel Skripkin <paskripkin at gmail.com>
Date: Fri, 2 Aug 2024 17:02:16 +0300
Subject: [PATCH 4/4] clang/csa: dump SVal of bitcast() and array[bitcast()]

---
 clang/test/Analysis/exercise-ps.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/clang/test/Analysis/exercise-ps.c b/clang/test/Analysis/exercise-ps.c
index 4b483b1a88a2f..50643d5b04687 100644
--- a/clang/test/Analysis/exercise-ps.c
+++ b/clang/test/Analysis/exercise-ps.c
@@ -6,6 +6,8 @@
 // Just exercise the analyzer on code that has at one point caused issues
 // (i.e., no assertions or crashes).
 
+void clang_analyzer_dump_int(int);
+
 static void f1(const char *x, char *y) {
   while (*x != 0) {
     *y++ = *x++;
@@ -39,5 +41,8 @@ void f4(char *array) {
 
   _Static_assert(sizeof(int) == 4, "Wrong triple for the test");
 
+  clang_analyzer_dump_int(__builtin_bit_cast(int, b)); // expected-warning {{lazyCompoundVal}}
+  clang_analyzer_dump_int(array[__builtin_bit_cast(int, b)]); // expected-warning {{Unknown}}
+
   array[__builtin_bit_cast(int, b)] = 0x10; // no crash
 }



More information about the cfe-commits mailing list