[clang] [analyzer] Add hack in ArrayBound to cover up missing casts (PR #127117)

DonĂ¡t Nagy via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 13 11:55:38 PST 2025


================
@@ -188,29 +189,50 @@ int test_cast_to_unsigned(signed char x) {
   if (x >= 0)
     return x;
   // FIXME: Here the analyzer ignores the signed -> unsigned cast, and manages to
-  // load a negative value from an unsigned variable. This causes an underflow
-  // report, which is an ugly false positive.
+  // load a negative value from an unsigned variable.
   // The underlying issue is tracked by Github ticket #39492.
   clang_analyzer_value(y); // expected-warning {{8s:{ [-128, -1] } }}
-  return table[y]; // expected-warning {{Out of bound access to memory preceding}}
+  // However, a hack in the ArrayBound checker suppresses the false positive
+  // underflow report that would be generated here.
+  return table[y]; // no-warning
 }
 
 int test_cast_to_unsigned_overflow(signed char x) {
   unsigned char y = x;
   if (x >= 0)
     return x;
-  // A variant of 'test_cast_to_unsigned' where the correct behavior would be
-  // an overflow report (because the negative values are cast to `unsigned
-  // char` values that are too large).
-  // FIXME: See comment in 'test_cast_to_unsigned'.
+  // FIXME: As in 'test_cast_to_unsigned', the analyzer thinks that this
+  // unsigned variable contains a negative value.
   clang_analyzer_value(y); // expected-warning {{8s:{ [-128, -1] } }}
-  return small_table[y]; // expected-warning {{Out of bound access to memory preceding}}
+  // FIXME: The following subscript expression should produce an overflow
+  // report (because negative signed char corresponds to unsigned char >= 128);
+  // but the hack in ArrayBound just silences reports and cannot "restore" the
+  // real execution paths.
+  return small_table[y]; // no-warning
+}
+
+int test_cast_to_unsigned_with_ptr_arith(signed char x) {
+  unsigned char y = x;
+  int *p = table - 10;
+
+  if (x >= 0)
+    return x;
+  // FIXME: As in 'test_cast_to_unsigned', the analyzer thinks that this
+  // unsigned variable contains a negative value.
+  clang_analyzer_value(y); // expected-warning {{8s:{ [-128, -1] } }}
+  // In this case, the hack in ArrayBound cannot suppress the false positive
+  // underflow report because 'p' is not the beginning of a memory region, so
+  // it cannot clearly say that an unsigned index guarantees no overflow.
+  // However, we still don't get an underflow report because (for some unclear
+  // reason) the analyzer fails to evaluate this more complex expression.
----------------
NagyDonat wrote:

I expected that this test case would demonstrate a shortcoming of my hacky report suppression -- but I was surprised to see that this case does not produce a false positive underflow report.

I verified with some manual debugging that my `isOffsetObviouslyNonnegative()` branch does not trigger in this testcase. The disappearance of the report is caused by something else -- perhaps the increased complexity of the expression?

https://github.com/llvm/llvm-project/pull/127117


More information about the cfe-commits mailing list