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

2024-06-24 Thread Balázs Kéri via cfe-commits

https://github.com/balazske closed 
https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-19 Thread Balázs Kéri via cfe-commits

https://github.com/balazske updated 
https://github.com/llvm/llvm-project/pull/95899

From 1eb6e7ebde0e97e1cd077dc27ffd3ebd6ed0e93d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= 
Date: Tue, 18 Jun 2024 10:09:24 +0200
Subject: [PATCH 1/4] [clang][analyzer] Add notes to PointerSubChecker

Notes are added to indicate the array declarations of the
arrays in a found invalid pointer subtraction.
---
 .../Checkers/PointerSubChecker.cpp| 45 ---
 clang/test/Analysis/pointer-sub-notes.c   | 34 ++
 2 files changed, 64 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/Analysis/pointer-sub-notes.c

diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b73534136fdf0..a983e66df0818 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -43,8 +43,6 @@ class PointerSubChecker
   bool checkArrayBounds(CheckerContext , const Expr *E,
 const ElementRegion *ElemReg,
 const MemRegion *Reg) const;
-  void reportBug(CheckerContext , const Expr *E,
- const llvm::StringLiteral ) const;
 
 public:
   void checkPreStmt(const BinaryOperator *B, CheckerContext ) const;
@@ -57,6 +55,14 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (!ElemReg)
 return true;
 
+  auto ReportBug = [&](const llvm::StringLiteral ) {
+if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+  auto R = std::make_unique(BT, Msg, N);
+  R->addRange(E->getSourceRange());
+  C.emitReport(std::move(R));
+}
+  };
+
   ProgramStateRef State = C.getState();
   const MemRegion *SuperReg = ElemReg->getSuperRegion();
   SValBuilder  = C.getSValBuilder();
@@ -64,7 +70,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (SuperReg == Reg) {
 if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
 I && (!I->isOne() && !I->isZero()))
-  reportBug(C, E, Msg_BadVarIndex);
+  ReportBug(Msg_BadVarIndex);
 return false;
   }
 
@@ -77,7 +83,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_LargeArrayIndex);
+  ReportBug(Msg_LargeArrayIndex);
   return false;
 }
   }
@@ -89,22 +95,13 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = State->assume(*IndexTooSmall);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_NegativeArrayIndex);
+  ReportBug(Msg_NegativeArrayIndex);
   return false;
 }
   }
   return true;
 }
 
-void PointerSubChecker::reportBug(CheckerContext , const Expr *E,
-  const llvm::StringLiteral ) const {
-  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
-auto R = std::make_unique(BT, Msg, N);
-R->addRange(E->getSourceRange());
-C.emitReport(std::move(R));
-  }
-}
-
 void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
  CheckerContext ) const {
   // When doing pointer subtraction, if the two pointers do not point to the
@@ -136,6 +133,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
   if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR))
 return;
 
+  const ValueDecl *DiffDeclL = nullptr;
+  const ValueDecl *DiffDeclR = nullptr;
+
   if (ElemLR && ElemRR) {
 const MemRegion *SuperLR = ElemLR->getSuperRegion();
 const MemRegion *SuperRR = ElemRR->getSuperRegion();
@@ -144,9 +144,24 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
 // Allow arithmetic on different symbolic regions.
 if (isa(SuperLR) || isa(SuperRR))
   return;
+if (const auto *SuperDLR = dyn_cast(SuperLR))
+  DiffDeclL = SuperDLR->getDecl();
+if (const auto *SuperDRR = dyn_cast(SuperRR))
+  DiffDeclR = SuperDRR->getDecl();
   }
 
-  reportBug(C, B, Msg_MemRegionDifferent);
+  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+auto R =
+std::make_unique(BT, Msg_MemRegionDifferent, 
N);
+R->addRange(B->getSourceRange());
+if (DiffDeclL)
+  R->addNote("Array at the left-hand side of subtraction",
+ {DiffDeclL, C.getSourceManager()});
+if (DiffDeclR)
+  R->addNote("Array at the right-hand side of subtraction",
+ {DiffDeclR, C.getSourceManager()});
+C.emitReport(std::move(R));
+  }
 }
 
 void ento::registerPointerSubChecker(CheckerManager ) {
diff --git a/clang/test/Analysis/pointer-sub-notes.c 
b/clang/test/Analysis/pointer-sub-notes.c
new file mode 100644
index 0..dfdace3a58deb
--- /dev/null
+++ b/clang/test/Analysis/pointer-sub-notes.c
@@ -0,0 +1,34 @@
+// 

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

2024-06-19 Thread Balázs Kéri via cfe-commits


@@ -144,9 +144,24 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
 // Allow arithmetic on different symbolic regions.
 if (isa(SuperLR) || isa(SuperRR))
   return;
+if (const auto *SuperDLR = dyn_cast(SuperLR))
+  DiffDeclL = SuperDLR->getDecl();
+if (const auto *SuperDRR = dyn_cast(SuperRR))
+  DiffDeclR = SuperDRR->getDecl();

balazske wrote:

Warning is now omitted if both would be at the same declaration.

https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-19 Thread Balázs Kéri via cfe-commits

https://github.com/balazske updated 
https://github.com/llvm/llvm-project/pull/95899

From 1eb6e7ebde0e97e1cd077dc27ffd3ebd6ed0e93d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= 
Date: Tue, 18 Jun 2024 10:09:24 +0200
Subject: [PATCH 1/3] [clang][analyzer] Add notes to PointerSubChecker

Notes are added to indicate the array declarations of the
arrays in a found invalid pointer subtraction.
---
 .../Checkers/PointerSubChecker.cpp| 45 ---
 clang/test/Analysis/pointer-sub-notes.c   | 34 ++
 2 files changed, 64 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/Analysis/pointer-sub-notes.c

diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b73534136fdf0..a983e66df0818 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -43,8 +43,6 @@ class PointerSubChecker
   bool checkArrayBounds(CheckerContext , const Expr *E,
 const ElementRegion *ElemReg,
 const MemRegion *Reg) const;
-  void reportBug(CheckerContext , const Expr *E,
- const llvm::StringLiteral ) const;
 
 public:
   void checkPreStmt(const BinaryOperator *B, CheckerContext ) const;
@@ -57,6 +55,14 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (!ElemReg)
 return true;
 
+  auto ReportBug = [&](const llvm::StringLiteral ) {
+if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+  auto R = std::make_unique(BT, Msg, N);
+  R->addRange(E->getSourceRange());
+  C.emitReport(std::move(R));
+}
+  };
+
   ProgramStateRef State = C.getState();
   const MemRegion *SuperReg = ElemReg->getSuperRegion();
   SValBuilder  = C.getSValBuilder();
@@ -64,7 +70,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (SuperReg == Reg) {
 if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
 I && (!I->isOne() && !I->isZero()))
-  reportBug(C, E, Msg_BadVarIndex);
+  ReportBug(Msg_BadVarIndex);
 return false;
   }
 
@@ -77,7 +83,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_LargeArrayIndex);
+  ReportBug(Msg_LargeArrayIndex);
   return false;
 }
   }
@@ -89,22 +95,13 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = State->assume(*IndexTooSmall);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_NegativeArrayIndex);
+  ReportBug(Msg_NegativeArrayIndex);
   return false;
 }
   }
   return true;
 }
 
-void PointerSubChecker::reportBug(CheckerContext , const Expr *E,
-  const llvm::StringLiteral ) const {
-  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
-auto R = std::make_unique(BT, Msg, N);
-R->addRange(E->getSourceRange());
-C.emitReport(std::move(R));
-  }
-}
-
 void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
  CheckerContext ) const {
   // When doing pointer subtraction, if the two pointers do not point to the
@@ -136,6 +133,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
   if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR))
 return;
 
+  const ValueDecl *DiffDeclL = nullptr;
+  const ValueDecl *DiffDeclR = nullptr;
+
   if (ElemLR && ElemRR) {
 const MemRegion *SuperLR = ElemLR->getSuperRegion();
 const MemRegion *SuperRR = ElemRR->getSuperRegion();
@@ -144,9 +144,24 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
 // Allow arithmetic on different symbolic regions.
 if (isa(SuperLR) || isa(SuperRR))
   return;
+if (const auto *SuperDLR = dyn_cast(SuperLR))
+  DiffDeclL = SuperDLR->getDecl();
+if (const auto *SuperDRR = dyn_cast(SuperRR))
+  DiffDeclR = SuperDRR->getDecl();
   }
 
-  reportBug(C, B, Msg_MemRegionDifferent);
+  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+auto R =
+std::make_unique(BT, Msg_MemRegionDifferent, 
N);
+R->addRange(B->getSourceRange());
+if (DiffDeclL)
+  R->addNote("Array at the left-hand side of subtraction",
+ {DiffDeclL, C.getSourceManager()});
+if (DiffDeclR)
+  R->addNote("Array at the right-hand side of subtraction",
+ {DiffDeclR, C.getSourceManager()});
+C.emitReport(std::move(R));
+  }
 }
 
 void ento::registerPointerSubChecker(CheckerManager ) {
diff --git a/clang/test/Analysis/pointer-sub-notes.c 
b/clang/test/Analysis/pointer-sub-notes.c
new file mode 100644
index 0..dfdace3a58deb
--- /dev/null
+++ b/clang/test/Analysis/pointer-sub-notes.c
@@ -0,0 +1,34 @@
+// 

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

2024-06-19 Thread Donát Nagy via cfe-commits

https://github.com/NagyDonat edited 
https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-19 Thread Donát Nagy via cfe-commits


@@ -32,3 +32,20 @@ void different_2() {
   int d = p2 - p1; // expected-warning{{Subtraction of two pointers that do 
not point into the same array is undefined behavior}} \
// expected-note{{Subtraction of two pointers that do not 
point into the same array is undefined behavior}}
 }
+
+int different_3() {
+  struct {
+int array[5];
+  } a, b;
+  return [3] - [2]; // expected-warning{{Subtraction of two 
pointers that do not point into the same array is undefined behavior}} \
+// expected-note{{Subtraction of two 
pointers that do not point into the same array is undefined behavior}}
+}
+
+int different_5() {

NagyDonat wrote:

```suggestion
int different_4() {
```
Very minor nitpick: `different_3` was followed by `different_5`.

https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-19 Thread Donát Nagy via cfe-commits


@@ -154,12 +154,14 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
 auto R =
 std::make_unique(BT, Msg_MemRegionDifferent, 
N);
 R->addRange(B->getSourceRange());
-if (DiffDeclL)
-  R->addNote("Array at the left-hand side of subtraction",
- {DiffDeclL, C.getSourceManager()});
-if (DiffDeclR)
-  R->addNote("Array at the right-hand side of subtraction",
- {DiffDeclR, C.getSourceManager()});
+if (DiffDeclL != DiffDeclR) {

NagyDonat wrote:

```suggestion
if (DiffDeclL != DiffDeclR) {
  // The declarations may be identical even if the regions are different,
  // if they are field regions within different objects:
  //   struct { int array[10]; } a, b;
  //   do_something_with(a.array[5] - b.array[5]);
  // In this case the notes would be confusing, so don't emit them.
```
Add a comment that explains this `if (DiffDeclL != DiffDeclR)` check because 
otherwise it would be very surprising.

https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-19 Thread Donát Nagy via cfe-commits

https://github.com/NagyDonat approved this pull request.

LGTM, thanks for the update. I added two minor edit suggestions, but after that 
the commit can be merged.

https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-19 Thread Donát Nagy via cfe-commits

https://github.com/NagyDonat edited 
https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-18 Thread Balázs Kéri via cfe-commits

https://github.com/balazske updated 
https://github.com/llvm/llvm-project/pull/95899

From 1eb6e7ebde0e97e1cd077dc27ffd3ebd6ed0e93d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= 
Date: Tue, 18 Jun 2024 10:09:24 +0200
Subject: [PATCH 1/2] [clang][analyzer] Add notes to PointerSubChecker

Notes are added to indicate the array declarations of the
arrays in a found invalid pointer subtraction.
---
 .../Checkers/PointerSubChecker.cpp| 45 ---
 clang/test/Analysis/pointer-sub-notes.c   | 34 ++
 2 files changed, 64 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/Analysis/pointer-sub-notes.c

diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b73534136fdf0..a983e66df0818 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -43,8 +43,6 @@ class PointerSubChecker
   bool checkArrayBounds(CheckerContext , const Expr *E,
 const ElementRegion *ElemReg,
 const MemRegion *Reg) const;
-  void reportBug(CheckerContext , const Expr *E,
- const llvm::StringLiteral ) const;
 
 public:
   void checkPreStmt(const BinaryOperator *B, CheckerContext ) const;
@@ -57,6 +55,14 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (!ElemReg)
 return true;
 
+  auto ReportBug = [&](const llvm::StringLiteral ) {
+if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+  auto R = std::make_unique(BT, Msg, N);
+  R->addRange(E->getSourceRange());
+  C.emitReport(std::move(R));
+}
+  };
+
   ProgramStateRef State = C.getState();
   const MemRegion *SuperReg = ElemReg->getSuperRegion();
   SValBuilder  = C.getSValBuilder();
@@ -64,7 +70,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (SuperReg == Reg) {
 if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
 I && (!I->isOne() && !I->isZero()))
-  reportBug(C, E, Msg_BadVarIndex);
+  ReportBug(Msg_BadVarIndex);
 return false;
   }
 
@@ -77,7 +83,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_LargeArrayIndex);
+  ReportBug(Msg_LargeArrayIndex);
   return false;
 }
   }
@@ -89,22 +95,13 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = State->assume(*IndexTooSmall);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_NegativeArrayIndex);
+  ReportBug(Msg_NegativeArrayIndex);
   return false;
 }
   }
   return true;
 }
 
-void PointerSubChecker::reportBug(CheckerContext , const Expr *E,
-  const llvm::StringLiteral ) const {
-  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
-auto R = std::make_unique(BT, Msg, N);
-R->addRange(E->getSourceRange());
-C.emitReport(std::move(R));
-  }
-}
-
 void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
  CheckerContext ) const {
   // When doing pointer subtraction, if the two pointers do not point to the
@@ -136,6 +133,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
   if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR))
 return;
 
+  const ValueDecl *DiffDeclL = nullptr;
+  const ValueDecl *DiffDeclR = nullptr;
+
   if (ElemLR && ElemRR) {
 const MemRegion *SuperLR = ElemLR->getSuperRegion();
 const MemRegion *SuperRR = ElemRR->getSuperRegion();
@@ -144,9 +144,24 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
 // Allow arithmetic on different symbolic regions.
 if (isa(SuperLR) || isa(SuperRR))
   return;
+if (const auto *SuperDLR = dyn_cast(SuperLR))
+  DiffDeclL = SuperDLR->getDecl();
+if (const auto *SuperDRR = dyn_cast(SuperRR))
+  DiffDeclR = SuperDRR->getDecl();
   }
 
-  reportBug(C, B, Msg_MemRegionDifferent);
+  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+auto R =
+std::make_unique(BT, Msg_MemRegionDifferent, 
N);
+R->addRange(B->getSourceRange());
+if (DiffDeclL)
+  R->addNote("Array at the left-hand side of subtraction",
+ {DiffDeclL, C.getSourceManager()});
+if (DiffDeclR)
+  R->addNote("Array at the right-hand side of subtraction",
+ {DiffDeclR, C.getSourceManager()});
+C.emitReport(std::move(R));
+  }
 }
 
 void ento::registerPointerSubChecker(CheckerManager ) {
diff --git a/clang/test/Analysis/pointer-sub-notes.c 
b/clang/test/Analysis/pointer-sub-notes.c
new file mode 100644
index 0..dfdace3a58deb
--- /dev/null
+++ b/clang/test/Analysis/pointer-sub-notes.c
@@ -0,0 +1,34 @@
+// 

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

2024-06-18 Thread Balázs Kéri via cfe-commits

balazske wrote:

I found difficult results from the checker where it is not obvious what the 
problem is.
One type is this case where a negative index is found (any of these results, or 
check the first one):
https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=curl_curl-7_66_0_pointersub=off=New=alpha.core.PointerSub
This type of problem is not fixed with the patch.

Other problem is when different arrays are found:
https://codechecker-demo.eastus.cloudapp.azure.com/Default/report-detail?run=vim_v8.2.1920_pointersub=off=New=alpha.core.PointerSub=5494864=9a4c8e84e0c5227d61f321ec217e88ec=%2Flocal%2Fpersistent_docker%2FCSA-measurements-driver-2913%2Fmeasurements_workspace%2Fvim%2Fsrc%2Fevalvars.c
This case should improve with the patch (but not tested yet).

https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-18 Thread Donát Nagy via cfe-commits


@@ -144,9 +144,24 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
 // Allow arithmetic on different symbolic regions.
 if (isa(SuperLR) || isa(SuperRR))
   return;
+if (const auto *SuperDLR = dyn_cast(SuperLR))
+  DiffDeclL = SuperDLR->getDecl();
+if (const auto *SuperDRR = dyn_cast(SuperRR))
+  DiffDeclR = SuperDRR->getDecl();

NagyDonat wrote:

Note that `FieldRegion`s are `DeclRegion`s, so these declarations may be data 
member declarations within a `struct` or `class`. This is usually not a 
problem, but there is a corner case where `SuperLR != SuperRR`, but the 
corresponding declarations are identical:
```
struct {
  int array[5];
} a, b;
int func(void) {
  return [3] - [2];
}
```
In this case the current code would place both notes onto the declaration of 
`field`, which would be confusing for the user.

Consider adding some code that handles this situation explicitly. (Either 
simply skip note creation when `DiffDeclL == DiffDeclR`, or create a 
specialized note for this case.)

https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-18 Thread Donát Nagy via cfe-commits

https://github.com/NagyDonat commented:

Looks good overall, I have one remark about a rare case that would require some 
specialized code.

https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-18 Thread Donát Nagy via cfe-commits

https://github.com/NagyDonat edited 
https://github.com/llvm/llvm-project/pull/95899
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-06-18 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Balázs Kéri (balazske)


Changes

Notes are added to indicate the array declarations of the arrays in a found 
invalid pointer subtraction.

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


2 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp (+30-15) 
- (added) clang/test/Analysis/pointer-sub-notes.c (+34) 


``diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b73534136fdf0..a983e66df0818 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -43,8 +43,6 @@ class PointerSubChecker
   bool checkArrayBounds(CheckerContext , const Expr *E,
 const ElementRegion *ElemReg,
 const MemRegion *Reg) const;
-  void reportBug(CheckerContext , const Expr *E,
- const llvm::StringLiteral ) const;
 
 public:
   void checkPreStmt(const BinaryOperator *B, CheckerContext ) const;
@@ -57,6 +55,14 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (!ElemReg)
 return true;
 
+  auto ReportBug = [&](const llvm::StringLiteral ) {
+if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+  auto R = std::make_unique(BT, Msg, N);
+  R->addRange(E->getSourceRange());
+  C.emitReport(std::move(R));
+}
+  };
+
   ProgramStateRef State = C.getState();
   const MemRegion *SuperReg = ElemReg->getSuperRegion();
   SValBuilder  = C.getSValBuilder();
@@ -64,7 +70,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (SuperReg == Reg) {
 if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
 I && (!I->isOne() && !I->isZero()))
-  reportBug(C, E, Msg_BadVarIndex);
+  ReportBug(Msg_BadVarIndex);
 return false;
   }
 
@@ -77,7 +83,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_LargeArrayIndex);
+  ReportBug(Msg_LargeArrayIndex);
   return false;
 }
   }
@@ -89,22 +95,13 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = State->assume(*IndexTooSmall);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_NegativeArrayIndex);
+  ReportBug(Msg_NegativeArrayIndex);
   return false;
 }
   }
   return true;
 }
 
-void PointerSubChecker::reportBug(CheckerContext , const Expr *E,
-  const llvm::StringLiteral ) const {
-  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
-auto R = std::make_unique(BT, Msg, N);
-R->addRange(E->getSourceRange());
-C.emitReport(std::move(R));
-  }
-}
-
 void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
  CheckerContext ) const {
   // When doing pointer subtraction, if the two pointers do not point to the
@@ -136,6 +133,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
   if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR))
 return;
 
+  const ValueDecl *DiffDeclL = nullptr;
+  const ValueDecl *DiffDeclR = nullptr;
+
   if (ElemLR && ElemRR) {
 const MemRegion *SuperLR = ElemLR->getSuperRegion();
 const MemRegion *SuperRR = ElemRR->getSuperRegion();
@@ -144,9 +144,24 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
 // Allow arithmetic on different symbolic regions.
 if (isa(SuperLR) || isa(SuperRR))
   return;
+if (const auto *SuperDLR = dyn_cast(SuperLR))
+  DiffDeclL = SuperDLR->getDecl();
+if (const auto *SuperDRR = dyn_cast(SuperRR))
+  DiffDeclR = SuperDRR->getDecl();
   }
 
-  reportBug(C, B, Msg_MemRegionDifferent);
+  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+auto R =
+std::make_unique(BT, Msg_MemRegionDifferent, 
N);
+R->addRange(B->getSourceRange());
+if (DiffDeclL)
+  R->addNote("Array at the left-hand side of subtraction",
+ {DiffDeclL, C.getSourceManager()});
+if (DiffDeclR)
+  R->addNote("Array at the right-hand side of subtraction",
+ {DiffDeclR, C.getSourceManager()});
+C.emitReport(std::move(R));
+  }
 }
 
 void ento::registerPointerSubChecker(CheckerManager ) {
diff --git a/clang/test/Analysis/pointer-sub-notes.c 
b/clang/test/Analysis/pointer-sub-notes.c
new file mode 100644
index 0..dfdace3a58deb
--- /dev/null
+++ b/clang/test/Analysis/pointer-sub-notes.c
@@ -0,0 +1,34 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.PointerSub 
-analyzer-output=text -verify %s
+
+void negative_1() {
+  int a[3];
+  int x = -1;
+  // FIXME: should indicate that 'x' is -1
+  int d = [x] - [0]; // 

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

2024-06-18 Thread via cfe-commits

llvmbot wrote:




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

Author: Balázs Kéri (balazske)


Changes

Notes are added to indicate the array declarations of the arrays in a found 
invalid pointer subtraction.

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


2 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp (+30-15) 
- (added) clang/test/Analysis/pointer-sub-notes.c (+34) 


``diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b73534136fdf0..a983e66df0818 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -43,8 +43,6 @@ class PointerSubChecker
   bool checkArrayBounds(CheckerContext , const Expr *E,
 const ElementRegion *ElemReg,
 const MemRegion *Reg) const;
-  void reportBug(CheckerContext , const Expr *E,
- const llvm::StringLiteral ) const;
 
 public:
   void checkPreStmt(const BinaryOperator *B, CheckerContext ) const;
@@ -57,6 +55,14 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (!ElemReg)
 return true;
 
+  auto ReportBug = [&](const llvm::StringLiteral ) {
+if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+  auto R = std::make_unique(BT, Msg, N);
+  R->addRange(E->getSourceRange());
+  C.emitReport(std::move(R));
+}
+  };
+
   ProgramStateRef State = C.getState();
   const MemRegion *SuperReg = ElemReg->getSuperRegion();
   SValBuilder  = C.getSValBuilder();
@@ -64,7 +70,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (SuperReg == Reg) {
 if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
 I && (!I->isOne() && !I->isZero()))
-  reportBug(C, E, Msg_BadVarIndex);
+  ReportBug(Msg_BadVarIndex);
 return false;
   }
 
@@ -77,7 +83,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_LargeArrayIndex);
+  ReportBug(Msg_LargeArrayIndex);
   return false;
 }
   }
@@ -89,22 +95,13 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = State->assume(*IndexTooSmall);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_NegativeArrayIndex);
+  ReportBug(Msg_NegativeArrayIndex);
   return false;
 }
   }
   return true;
 }
 
-void PointerSubChecker::reportBug(CheckerContext , const Expr *E,
-  const llvm::StringLiteral ) const {
-  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
-auto R = std::make_unique(BT, Msg, N);
-R->addRange(E->getSourceRange());
-C.emitReport(std::move(R));
-  }
-}
-
 void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
  CheckerContext ) const {
   // When doing pointer subtraction, if the two pointers do not point to the
@@ -136,6 +133,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
   if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR))
 return;
 
+  const ValueDecl *DiffDeclL = nullptr;
+  const ValueDecl *DiffDeclR = nullptr;
+
   if (ElemLR && ElemRR) {
 const MemRegion *SuperLR = ElemLR->getSuperRegion();
 const MemRegion *SuperRR = ElemRR->getSuperRegion();
@@ -144,9 +144,24 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
 // Allow arithmetic on different symbolic regions.
 if (isa(SuperLR) || isa(SuperRR))
   return;
+if (const auto *SuperDLR = dyn_cast(SuperLR))
+  DiffDeclL = SuperDLR->getDecl();
+if (const auto *SuperDRR = dyn_cast(SuperRR))
+  DiffDeclR = SuperDRR->getDecl();
   }
 
-  reportBug(C, B, Msg_MemRegionDifferent);
+  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+auto R =
+std::make_unique(BT, Msg_MemRegionDifferent, 
N);
+R->addRange(B->getSourceRange());
+if (DiffDeclL)
+  R->addNote("Array at the left-hand side of subtraction",
+ {DiffDeclL, C.getSourceManager()});
+if (DiffDeclR)
+  R->addNote("Array at the right-hand side of subtraction",
+ {DiffDeclR, C.getSourceManager()});
+C.emitReport(std::move(R));
+  }
 }
 
 void ento::registerPointerSubChecker(CheckerManager ) {
diff --git a/clang/test/Analysis/pointer-sub-notes.c 
b/clang/test/Analysis/pointer-sub-notes.c
new file mode 100644
index 0..dfdace3a58deb
--- /dev/null
+++ b/clang/test/Analysis/pointer-sub-notes.c
@@ -0,0 +1,34 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.core.PointerSub 
-analyzer-output=text -verify %s
+
+void negative_1() {
+  int a[3];
+  int x = -1;
+  // FIXME: should indicate that 'x' is -1
+  int d = [x] - [0]; 

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

2024-06-18 Thread Balázs Kéri via cfe-commits

https://github.com/balazske created 
https://github.com/llvm/llvm-project/pull/95899

Notes are added to indicate the array declarations of the arrays in a found 
invalid pointer subtraction.

From 1eb6e7ebde0e97e1cd077dc27ffd3ebd6ed0e93d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bal=C3=A1zs=20K=C3=A9ri?= 
Date: Tue, 18 Jun 2024 10:09:24 +0200
Subject: [PATCH] [clang][analyzer] Add notes to PointerSubChecker

Notes are added to indicate the array declarations of the
arrays in a found invalid pointer subtraction.
---
 .../Checkers/PointerSubChecker.cpp| 45 ---
 clang/test/Analysis/pointer-sub-notes.c   | 34 ++
 2 files changed, 64 insertions(+), 15 deletions(-)
 create mode 100644 clang/test/Analysis/pointer-sub-notes.c

diff --git a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
index b73534136fdf0..a983e66df0818 100644
--- a/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp
@@ -43,8 +43,6 @@ class PointerSubChecker
   bool checkArrayBounds(CheckerContext , const Expr *E,
 const ElementRegion *ElemReg,
 const MemRegion *Reg) const;
-  void reportBug(CheckerContext , const Expr *E,
- const llvm::StringLiteral ) const;
 
 public:
   void checkPreStmt(const BinaryOperator *B, CheckerContext ) const;
@@ -57,6 +55,14 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (!ElemReg)
 return true;
 
+  auto ReportBug = [&](const llvm::StringLiteral ) {
+if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+  auto R = std::make_unique(BT, Msg, N);
+  R->addRange(E->getSourceRange());
+  C.emitReport(std::move(R));
+}
+  };
+
   ProgramStateRef State = C.getState();
   const MemRegion *SuperReg = ElemReg->getSuperRegion();
   SValBuilder  = C.getSValBuilder();
@@ -64,7 +70,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
   if (SuperReg == Reg) {
 if (const llvm::APSInt *I = SVB.getKnownValue(State, ElemReg->getIndex());
 I && (!I->isOne() && !I->isZero()))
-  reportBug(C, E, Msg_BadVarIndex);
+  ReportBug(Msg_BadVarIndex);
 return false;
   }
 
@@ -77,7 +83,7 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = C.getState()->assume(*IndexTooLarge);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_LargeArrayIndex);
+  ReportBug(Msg_LargeArrayIndex);
   return false;
 }
   }
@@ -89,22 +95,13 @@ bool PointerSubChecker::checkArrayBounds(CheckerContext , 
const Expr *E,
 ProgramStateRef S1, S2;
 std::tie(S1, S2) = State->assume(*IndexTooSmall);
 if (S1 && !S2) {
-  reportBug(C, E, Msg_NegativeArrayIndex);
+  ReportBug(Msg_NegativeArrayIndex);
   return false;
 }
   }
   return true;
 }
 
-void PointerSubChecker::reportBug(CheckerContext , const Expr *E,
-  const llvm::StringLiteral ) const {
-  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
-auto R = std::make_unique(BT, Msg, N);
-R->addRange(E->getSourceRange());
-C.emitReport(std::move(R));
-  }
-}
-
 void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
  CheckerContext ) const {
   // When doing pointer subtraction, if the two pointers do not point to the
@@ -136,6 +133,9 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
   if (!checkArrayBounds(C, B->getRHS(), ElemRR, LR))
 return;
 
+  const ValueDecl *DiffDeclL = nullptr;
+  const ValueDecl *DiffDeclR = nullptr;
+
   if (ElemLR && ElemRR) {
 const MemRegion *SuperLR = ElemLR->getSuperRegion();
 const MemRegion *SuperRR = ElemRR->getSuperRegion();
@@ -144,9 +144,24 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator 
*B,
 // Allow arithmetic on different symbolic regions.
 if (isa(SuperLR) || isa(SuperRR))
   return;
+if (const auto *SuperDLR = dyn_cast(SuperLR))
+  DiffDeclL = SuperDLR->getDecl();
+if (const auto *SuperDRR = dyn_cast(SuperRR))
+  DiffDeclR = SuperDRR->getDecl();
   }
 
-  reportBug(C, B, Msg_MemRegionDifferent);
+  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
+auto R =
+std::make_unique(BT, Msg_MemRegionDifferent, 
N);
+R->addRange(B->getSourceRange());
+if (DiffDeclL)
+  R->addNote("Array at the left-hand side of subtraction",
+ {DiffDeclL, C.getSourceManager()});
+if (DiffDeclR)
+  R->addNote("Array at the right-hand side of subtraction",
+ {DiffDeclR, C.getSourceManager()});
+C.emitReport(std::move(R));
+  }
 }
 
 void ento::registerPointerSubChecker(CheckerManager ) {
diff --git a/clang/test/Analysis/pointer-sub-notes.c 
b/clang/test/Analysis/pointer-sub-notes.c
new file mode 100644
index