[clang] [clang][analyzer] Add more notes to PointerSubChecker (PR #102432)

via cfe-commits cfe-commits at lists.llvm.org
Thu Aug 8 00:53:19 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balázs Kéri (balazske)

<details>
<summary>Changes</summary>

Notes appear at out-of-range array index for index value and array size.

---
Full diff: https://github.com/llvm/llvm-project/pull/102432.diff


2 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp (+23-7) 
- (modified) clang/test/Analysis/pointer-sub.c (+25-7) 


``````````diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b856b0edc61514..1b215cc59c95ae 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -73,31 +73,47 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext &C, const Expr *E,
   if (!ElemReg)
     return true;
 
+  ProgramStateRef State = C.getState();
+  SValBuilder &SVB = C.getSValBuilder();
+
   const MemRegion *SuperReg = ElemReg->getSuperRegion();
   if (!isArrayVar(SuperReg))
     return true;
+  DefinedOrUnknownSVal ElemCount =
+      getDynamicElementCount(State, SuperReg, SVB, ElemReg->getElementType());
+
+  const ValueDecl *SuperDecl = nullptr;
+  if (auto *DR = dyn_cast<DeclRegion>(SuperReg))
+    SuperDecl = DR->getDecl();
+  const llvm::APSInt *ElemCountKnown = SVB.getKnownValue(State, ElemCount);
+  const llvm::APSInt *IndexKnown =
+      SVB.getKnownValue(State, ElemReg->getIndex());
 
   auto ReportBug = [&](const llvm::StringLiteral &Msg) {
     if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
       auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
       R->addRange(E->getSourceRange());
+      if (SuperDecl && ElemCountKnown && SuperDecl->getType()->isArrayType()) {
+        std::string Msg =
+            llvm::formatv("Array of size {0} declared here", *ElemCountKnown);
+        R->addNote(Msg, {SuperDecl, C.getSourceManager()});
+      }
+      if (IndexKnown) {
+        std::string Msg =
+            llvm::formatv("Memory object indexed with {0}", *IndexKnown);
+        R->addNote(Msg, {E, C.getSourceManager(), C.getLocationContext()});
+      }
       C.emitReport(std::move(R));
     }
   };
 
-  ProgramStateRef State = C.getState();
-  SValBuilder &SVB = C.getSValBuilder();
-
   if (SuperReg == Reg) {
     // Case like `(&x + 1) - &x`. Only 1 or 0 is allowed as index.
-    if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
-        I && (!I->isOne() && !I->isZero()))
+    if (IndexKnown && (!IndexKnown->isOne() && !IndexKnown->isZero()))
       ReportBug(Msg_BadVarIndex);
     return false;
   }
 
-  DefinedOrUnknownSVal ElemCount =
-      getDynamicElementCount(State, SuperReg, SVB, ElemReg->getElementType());
   auto IndexTooLarge = SVB.evalBinOp(C.getState(), BO_GT, ElemReg->getIndex(),
                                      ElemCount, SVB.getConditionType())
                            .getAs<DefinedOrUnknownSVal>();
diff --git a/clang/test/Analysis/pointer-sub.c b/clang/test/Analysis/pointer-sub.c
index 194c8918899525..0ce8fe850ca0fe 100644
--- a/clang/test/Analysis/pointer-sub.c
+++ b/clang/test/Analysis/pointer-sub.c
@@ -1,7 +1,7 @@
 // RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.PointerSub -analyzer-output=text-minimal -verify %s
 
 void f1(void) {
-  int x, y, z[10];
+  int x, y, z[10]; // expected-note2{{Array of size 10 declared here}}
   int d = &y - &x; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
   d = z - &y; // expected-warning{{Subtraction of two pointers that do not point into the same array is undefined behavior}}
   d = &x - &x; // no-warning (subtraction of any two identical pointers is allowed)
@@ -9,18 +9,23 @@ void f1(void) {
   d = (&x + 1) - &x; // no-warning ('&x' is like a single-element array)
   d = &x - (&x + 1); // no-warning
   d = (&x + 0) - &x; // no-warning
-  d = (&x - 1) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}}
-  d = (&x + 2) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}}
+  d = (&x - 1) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}} \
+                     // expected-note{{Memory object indexed with -1}}
+  d = (&x + 2) - &x; // expected-warning{{Indexing the address of a variable with other than 1 at this place is undefined behavior}} \
+                     // expected-note{{Memory object indexed with 2}}
 
   d = (z + 9) - z; // no-warning (pointers to same array)
   d = (z + 10) - z; // no-warning (pointer to "one after the end")
-  d = (z + 11) - z; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}}
-  d = (z - 1) - z; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}}
+  d = (z + 11) - z; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}} \
+                    // expected-note{{Memory object indexed with 11}}
+  d = (z - 1) - z; // expected-warning{{Using a negative array index at pointer subtraction is undefined behavior}} \
+                   // expected-note{{Memory object indexed with -1}}
 }
 
 void f2(void) {
   int a[10], b[10], c; // expected-note{{Array at the left-hand side of subtraction}} \
-                       // expected-note2{{Array at the right-hand side of subtraction}}
+                       // expected-note2{{Array at the right-hand side of subtraction}} \
+                       // expected-note{{Array of size 10 declared here}}
   int *p = &a[2];
   int *q = &a[8];
   int d = q - p; // no-warning (pointers into the same array)
@@ -31,7 +36,8 @@ void f2(void) {
   q = a + 10;
   d = q - p; // no warning (use of pointer to one after the end is allowed)
   q = a + 11;
-  d = q - a; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}}
+  d = q - a; // expected-warning{{Using an array index greater than the array size at pointer subtraction is undefined behavior}} \
+             // expected-note{{Memory object indexed with 11}}
 
   d = &a[4] - a; // no-warning
   d = &a[2] - p; // no-warning
@@ -154,3 +160,15 @@ int f12() {
   init_S2(&s);
   return s.p1 - s.p2; // no-warning (pointers are unknown)
 }
+
+void f13() {
+  int a[0]; // expected-note2{{Array of size 0 declared here}}
+  int *p1 = a, *p2 = a, *p3 = a;
+  --p1;
+  ++p2;
+  int d1 = a - p1; // expected-warning{{negative array index}} \
+                   // expected-note{{Memory object indexed with -1}}
+  int d2 = a - p2; // expected-warning{{array index greater}} \
+                   // expected-note{{Memory object indexed with 1}}
+  int d3 = a - p3;
+}

``````````

</details>


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


More information about the cfe-commits mailing list