https://github.com/bozicrHT created 
https://github.com/llvm/llvm-project/pull/221213

`castRegion()` returns `nullopt` for `ElementRegion`s with symbolic indices, 
causing pointer casts to become `UnknownVal` and lose nullness information. 
Preserve the original region as a zero-offset view of the destination type, 
while stripping redundant cast views.

Update tests for symbolic pointer casts.


Fixes #220281 

From 9238bc2b15c782fc511a7a292572cafa63b16ca0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Radovan=20Bo=C5=BEi=C4=87?= <[email protected]>
Date: Fri, 4 Sep 2026 14:19:17 +0200
Subject: [PATCH] [clang][analyzer] Preserve symbolic-offset regions across
 pointer casts

When an ElementRegion has a symbolic index, `castRegion()` cannot
compute a concrete byte offset and returns `nullopt`. Preserve the
original region as a zero-offset view of the destination type and strip
redundant cast views.
---
 clang/lib/StaticAnalyzer/Core/Store.cpp     | 11 ++++--
 clang/test/Analysis/pr22954.c               |  5 ++-
 clang/test/Analysis/symbolic-pointer-cast.c | 42 +++++++++++++++++++++
 3 files changed, 52 insertions(+), 6 deletions(-)
 create mode 100644 clang/test/Analysis/symbolic-pointer-cast.c

diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp 
b/clang/lib/StaticAnalyzer/Core/Store.cpp
index 3b56dde1b56d6..0a91b452ee11d 100644
--- a/clang/lib/StaticAnalyzer/Core/Store.cpp
+++ b/clang/lib/StaticAnalyzer/Core/Store.cpp
@@ -175,10 +175,13 @@ std::optional<const MemRegion *> 
StoreManager::castRegion(const MemRegion *R,
       const RegionRawOffset &rawOff = elementR->getAsArrayOffset();
       const MemRegion *baseR = rawOff.getRegion();
 
-      // If we cannot compute a raw offset, throw up our hands and return
-      // a NULL MemRegion*.
-      if (!baseR)
-        return std::nullopt;
+      if (!baseR) {
+        const MemRegion *uncastedR = elementR->StripCasts(false);
+        if (IsSameRegionType(uncastedR, CanonPointeeTy))
+          return uncastedR;
+
+        return MakeElementRegion(cast<SubRegion>(uncastedR), PointeeTy);
+      }
 
       CharUnits off = rawOff.getOffset();
 
diff --git a/clang/test/Analysis/pr22954.c b/clang/test/Analysis/pr22954.c
index b3910da6c70ab..1a14d83ca2ae9 100644
--- a/clang/test/Analysis/pr22954.c
+++ b/clang/test/Analysis/pr22954.c
@@ -615,7 +615,8 @@ int f29(int i, int j, int k, int l, int m) {
   l29->s1[m] = 2;
   char input[] = {'a', 'b', 'c', 'd'};
   memcpy(l29->s1, input, 4);
-  clang_analyzer_eval(m29[0].s3[0] == 1); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval(m29[0].s3[0] == 1); // expected-warning{{UNKNOWN}}\
+  expected-warning{{Potential leak of memory pointed to by field 's4'}}
   clang_analyzer_eval(m29[0].s3[1] == 1); // expected-warning{{UNKNOWN}}
   clang_analyzer_eval(m29[0].s3[2] == 1); // expected-warning{{UNKNOWN}}
   clang_analyzer_eval(m29[0].s3[3] == 1); // expected-warning{{UNKNOWN}}
@@ -627,7 +628,7 @@ int f29(int i, int j, int k, int l, int m) {
   clang_analyzer_eval(m29[i].s3[1] == 1); // expected-warning{{UNKNOWN}}
   clang_analyzer_eval(m29[i].s3[2] == 1); // expected-warning{{UNKNOWN}}
   clang_analyzer_eval(m29[i].s3[3] == 1); // expected-warning{{UNKNOWN}}
-  clang_analyzer_eval(m29[j].s3[k] == 1); // expected-warning{{TRUE}}
+  clang_analyzer_eval(m29[j].s3[k] == 1); // expected-warning{{UNKNOWN}}
   clang_analyzer_eval(l29->s1[m] == 2); // expected-warning{{UNKNOWN}}
   // FIXME: Should warn that m29[i].s4 leaks. But not on the previous line,
   // because l29 and m29 alias.
diff --git a/clang/test/Analysis/symbolic-pointer-cast.c 
b/clang/test/Analysis/symbolic-pointer-cast.c
new file mode 100644
index 0000000000000..9804254808343
--- /dev/null
+++ b/clang/test/Analysis/symbolic-pointer-cast.c
@@ -0,0 +1,42 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify 
%s
+
+void clang_analyzer_eval(int);
+
+void symbolic_offset_pointer_cast_preserves_nonnull(_Bool i) {
+  unsigned char a[2];
+  unsigned char *q = a + i;
+  char *r = (char *)q;
+
+  clang_analyzer_eval(q != 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(r != 0); // expected-warning{{TRUE}}
+
+  if (!r)
+    *r = 0; // no-warning
+}
+
+void differently_sized_symbolic_offset_pointer_cast_preserves_nonnull(_Bool i) 
{
+  int a[2];
+  int *q = a + i;
+  char *r = (char *)q;
+  int *s = (int *)r;
+
+  clang_analyzer_eval(r != 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(s == q); // expected-warning{{TRUE}}
+
+  if (!r)
+    *r = 0; // no-warning
+}
+
+void symbolic_base_pointer_cast_preserves_nonnull(int *p, _Bool i) {
+  if (!p)
+    return;
+
+  int *q = p + i;
+  char *r = (char *)q;
+
+  clang_analyzer_eval(q != 0); // expected-warning{{TRUE}}
+  clang_analyzer_eval(r != 0); // expected-warning{{TRUE}}
+
+  if (!r)
+    *r = 0; // no-warning
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to