https://github.com/NagyDonat created 
https://github.com/llvm/llvm-project/pull/216077

The `security.ArrayBound` checker is to report potential out-of-bounds access 
when it detects that the accessed offset is tainted (potentially 
attacker-controlled).

However, until now this only reported cases where _overflow_ was possible with 
the tainted offset. (This is probably an accidental oversight -- in the old 
implementation it was easy to forget adding a second check that would report 
the "potential underflow with tainted offset" case.)

This commit corrects this oversight and ensures that potential underflow with a 
tainted offset is also correctly reported.

---

I will evaluate this change on our usual set of open source projects.

From 1e4bdff18bacff7fa9ece3a0dbf21298a93051c9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Don=C3=A1t=20Nagy?= <[email protected]>
Date: Thu, 13 Aug 2026 16:57:44 +0200
Subject: [PATCH] [analyzer] Implement potiential underflow warnings

The `security.ArrayBound` checker is to report potential out-of-bounds
access when it detects that the accessed offset is tainted (potentially
attacker-controlled).

However, until now this only reported cases where _overflow_ was
possible with the tainted offset. (This is probably an accidental
oversight -- in the old implementation it was easy to forget adding a
second check that would report the "potential underflow with tainted
offset" case.)

This commit corrects this oversight and ensures that potential underflow
with a tainted offset is also correctly reported.
---
 .../Checkers/ArrayBoundChecker.cpp            | 20 +++++++++----------
 .../test/Analysis/ArrayBound/verbose-tests.c  | 17 ++++++++++++++++
 2 files changed, 26 insertions(+), 11 deletions(-)

diff --git a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
index 9e4e8e83749ad..256b17154cd44 100644
--- a/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp
@@ -334,13 +334,15 @@ static BugDescription 
describeInvalidAccess(bounds::CheckResult Res,
           std::string(Buf)};
 }
 
-static BugDescription describeTaintBug(StringRef RegName, StringRef OffsetName,
-                                       bool AlsoMentionUnderflow) {
+static BugDescription describeTaintBug(bounds::CheckResult Res,
+                                       StringRef RegName,
+                                       StringRef OffsetName) {
   return {formatv("Potential out of bound access to {0} with tainted {1}",
                   RegName, OffsetName),
-          formatv("Access of {0} with a tainted {1} that may be {2}too large",
-                  RegName, OffsetName,
-                  AlsoMentionUnderflow ? "negative or " : "")};
+          formatv("Access of {0} with a tainted {1} that may be{2}{3}{4}.",
+                  RegName, OffsetName, Res.mayUnderflow() ? " negative" : "",
+                  (Res.mayUnderflow() && Res.mayOverflow()) ? " or" : "",
+                  Res.mayOverflow() ? " too large" : "")};
 }
 
 /// When the access was ambiguous (that is, mayBeInBounds() && mayBeInvalid()),
@@ -480,10 +482,7 @@ void ArrayBoundChecker::handleAccessExpr(const Expr *E,
       return;
     }
 
-    // FIXME: Remove `Res.mayOverflow()` and provide diagnostics for the case
-    // when the tainted access operation cannot overflow but can underflow.
-    // (This is an NFC commit, so I cannot include this improvement.)
-    if (Res.mayOverflow() && isTainted(State, ByteOffset)) {
+    if (isTainted(State, ByteOffset)) {
       // Diagnostic detail: saying "tainted offset" is always correct, but
       // the common case is that 'idx' is tainted in 'arr[idx]' and then it's
       // nicer to say "tainted index".
@@ -492,8 +491,7 @@ void ArrayBoundChecker::handleAccessExpr(const Expr *E,
         if (isTainted(State, ASE->getIdx(), C.getStackFrame()))
           OffsetName = "index";
 
-      BugDescription Desc =
-          describeTaintBug(RegName, OffsetName, Res.mayUnderflow());
+      BugDescription Desc = describeTaintBug(Res, RegName, OffsetName);
       reportOOB(C, State, Desc, ByteOffset, Extent, /*IsTaintBug=*/true);
       return;
     }
diff --git a/clang/test/Analysis/ArrayBound/verbose-tests.c 
b/clang/test/Analysis/ArrayBound/verbose-tests.c
index c0b1f2a8ae6be..81b5001c60f89 100644
--- a/clang/test/Analysis/ArrayBound/verbose-tests.c
+++ b/clang/test/Analysis/ArrayBound/verbose-tests.c
@@ -100,6 +100,23 @@ void taintedIndexNonneg(void) {
   // expected-note@-2 {{Access of 'TenElements' with a tainted index that may 
be too large}}
 }
 
+void taintedIndexNonlarge(void) {
+  int index;
+  scanf("%d", &index);
+  // expected-note@-1 {{Taint originated here}}
+  // expected-note@-2 {{Taint propagated to the 2nd argument}}
+
+  // expected-note@+2 {{Assuming 'index' is < 10}}
+  // expected-note@+1 {{Taking false branch}}
+  if (index >= 10)
+    return;
+
+  TenElements[index] = 5;
+  // expected-warning@-1 {{Potential out of bound access to 'TenElements' with 
tainted index}}
+  // expected-note@-2 {{Access of 'TenElements' with a tainted index that may 
be negative}}
+}
+
+
 void taintedIndexUnsigned(void) {
   unsigned index;
   scanf("%u", &index);

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

Reply via email to