[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-07-15 Thread Manas Gupta via Phabricator via cfe-commits
manas created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: teemperor.
manas requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Prior to this, the solver was only able to verify whether two symbols
are equal/unequal, only when constants were involved. This patch allows
the solver to work over ranges as well.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D106102

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -465,3 +465,41 @@
 clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
   }
 }
+
+void testEqualityRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when ranges are not overlapping
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (a >= 20 && a <= 50 && b >= 20 && b <= 50) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -20 && c <= 20 && d >= -20 && d <= 20) {
+clang_analyzer_eval((c != d) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (a >= 100 && a <= 200 && b >= 150 && b <= 300) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -80 && c <= -50 && d >= -100 && d <= -75) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (a >= 500 && a <= 1000 && b >= 750 && b <= 1000) {
+clang_analyzer_eval((a != b) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -1000 && c <= -500 && d <= -500 && d >= -750) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{UNKNOWN}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -952,6 +952,8 @@
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
RangeSet RHS, QualType T) {
 switch (Op) {
+case BO_NE:
+  return VisitBinaryOperator(LHS, RHS, T);
 case BO_Or:
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_And:
@@ -1218,6 +1220,27 @@
 //   Range-based reasoning about symbolic operations
 
//===--===//
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS, Range 
RHS,
+   QualType T) {
+
+  // When both the ranges are non-overlapping then all possible pairs of (x, y)
+  // in LHS, RHS will satisfy expression (x != y)
+  if ((LHS.To() < RHS.From()) || (RHS.To() < LHS.From())) {
+return getTrueRange(T);
+  }
+
+  // If both ranges contain only one same Point then the expression will always
+  // return true
+  if ((LHS.From() == RHS.To()) && (LHS.To() == RHS.To()) &&
+  (LHS.From() == RHS.From())) {
+return getFalseRange(T);
+  }
+
+  // In all other cases, the resulting range cannot be deduced.
+  return RangeFactory.getEmptySet();
+}
+
 template <>
 RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS, Range 
RHS,
QualType T) {


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -465,3 +465,41 @@
 clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
   }
 }
+
+void testEqualityRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when ranges are not overlapping
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (a >= 20 && a <= 50 && b >= 20 && b <= 50) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -20 && c <= 20 && d >= -20 && d <= 20) {
+clang_analyzer_eval((c != d) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Check

[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-07-16 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1223-1225
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS, Range 
RHS,
+   QualType T) {

vsavchenko wrote:
> I think it should be a specialization for another `VisitBinaryOperator`.
> In the switch, you can see that we give range sets for `LHS` and `RHS`, so 
> how does it work?
> There is a function in between (also `VisitBinaryOperator`) that creates 
> simple ranges out of range sets and ask to visit binary operator for those.  
> You can specialize it instead since we can simply check for empty 
> intersection of range sets.
I went through the code and understood that part. I agree that this should be a 
specialized case for VisitBinaryOperator. So I understand it in this way:

1. Creating a new `VisitBinaryOperator(Range,Range,QualType)` which can check 
for empty intersections.
2. It will then call to appropriate functions (like 
`VisittBinaryOperator` and others.)



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1241
+  // In all other cases, the resulting range cannot be deduced.
+  return RangeFactory.getEmptySet();
+}

vsavchenko wrote:
> Empty range set means "This situation is IMPOSSIBLE".  Is that what you want 
> here?
True! That's incorrect. We cannot find a good rangeset. Should I rather return 
the entire RangeSet inferred from `T`?



Comment at: clang/test/Analysis/constant-folding.c:470-504
+  // Checks when ranges are not overlapping
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}

vsavchenko wrote:
> Did you try it in debugger, do we get inside of your function?
Yes, the function is being reached.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-07-20 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

Here is the proof of correctness of the algorithm using Z3: 
https://gist.github.com/weirdsmiley/ad6a9dbf3370e96d29f9e90068931d25


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105273: [analyzer] Introduce range-based reasoning for subtraction operator

2021-07-20 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

Here is the proof using Z3: 
https://gist.github.com/weirdsmiley/8a35a0e1f55f310e3566cbd47555491a


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105273/new/

https://reviews.llvm.org/D105273

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106416: [analyzer] Fix build dependency issues for SATest

2021-07-20 Thread Manas Gupta via Phabricator via cfe-commits
manas created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: teemperor.
manas requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

It comprises of two specific changes:

1. Fixes cmake's unmet dependency by upgrading it.
2. Adds ccache to the build dependency list, which can be used for 
LLVM_CCACHE_BUILD cmake option for boosting rebuilds.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D106416

Files:
  clang/utils/analyzer/Dockerfile


Index: clang/utils/analyzer/Dockerfile
===
--- clang/utils/analyzer/Dockerfile
+++ clang/utils/analyzer/Dockerfile
@@ -17,8 +17,9 @@
 gettext=0.19.8.1* \
 python3=3.6.7-1~18.04 \
 python3-pip=9.0.1-2.3* \
-cmake=3.20.5* \
-ninja-build=1.8.2-1
+cmake=3.21.0* \
+ninja-build=1.8.2-1 \
+ccache=3.4*
 
 # box2d dependencies
 RUN apt-get install -y \


Index: clang/utils/analyzer/Dockerfile
===
--- clang/utils/analyzer/Dockerfile
+++ clang/utils/analyzer/Dockerfile
@@ -17,8 +17,9 @@
 gettext=0.19.8.1* \
 python3=3.6.7-1~18.04 \
 python3-pip=9.0.1-2.3* \
-cmake=3.20.5* \
-ninja-build=1.8.2-1
+cmake=3.21.0* \
+ninja-build=1.8.2-1 \
+ccache=3.4*
 
 # box2d dependencies
 RUN apt-get install -y \
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-04-06 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 420962.
manas added a comment.
Herald added a project: All.

Fix test cases to make them reachable via VisiBinaryOperator and using 
getConcreteValue()


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,59 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, unsigned int u3,
+int s1, int s2, int s3) {
+
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval(s1 != s2); // expected-warning{{TRUE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for comparison between different types
+  // Using different variables as previous constraints may interfere in the
+  // reasoning.
+  if (u3 <= 255 && s3 < 0) {
+// u3: [0, 255], s3: [INT_MIN, -1]
+clang_analyzer_eval(u3 != s3); // expected-warning{{TRUE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -20,8 +20,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -1136,18 +1136,7 @@
   }
 
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
-   RangeSet RHS, QualType T) {
-switch (Op) {
-case BO_Or:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_And:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_Rem:
-  return VisitBinaryOperator(LHS, RHS, T);
-default:
-  return infer(T);
-}
-  }
+   RangeSet RHS, QualType T);
 
   //===--===//
   // Ranges and operators
@@ -1412,6 +1401,49 @@
 //   Range-based reasoning about symbolic operations
 //===--===//
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,
+   RangeSet RHS,
+   QualType T) {
+
+  // We must check for empty RangeSets. This gets done via VisitBinaryOperator
+  // for other operators, but BO_NE is handled specifically.
+  if (LHS.isEmpty() || RHS.isEmpty()) {
+return RangeFactory.getEmptySet();
+  }
+
+  Range CoarseLHS = fillGaps(LHS);
+  Range CoarseRHS = fillGaps(RHS);
+
+  APSIntType ResultType = ValueFactory.getAPSIntType(T);
+
+  auto ConvertedCoarseLHS = convert(CoarseLHS, ResultType);
+  auto ConvertedCoarseRHS = convert(CoarseRHS, ResultType);
+
+  if (!ConvertedCoarseLHS || !ConvertedCoarseRHS) {
+return infer(T);
+  }
+
+  // When both the Ranges are non-overlapping then all possible pairs of (x, y)
+  // in ConvertedLHS, ConvertedR

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-04-06 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

@steakhal apologies for holding onto this for so long. I managed to fix 
previously untestable test cases. The issue was that I was building expressions 
as `(u1 != u2) != 0` and the solver was canonicalizing this to an equivalent 
`BO_EQ` expression. That's why, it wasn't reaching 
`VisitBinaryOperator()`. So I changed all tests as following: `(u1 != 
u2)` (removing the latter `!= 0` part. Also, I utilized the 
`getConcreteValue()` for checking of single APSInt in the RangeSets.

Apart from this, I am building for the coverage reports (which I will upload 
later).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-04-06 Thread Manas Gupta via Phabricator via cfe-commits
manas marked 2 inline comments as done.
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1272-1273
+  // (x != y).
+  if ((ConvertedLHS.getMaxValue() < ConvertedRHS.getMinValue()) ||
+  (ConvertedLHS.getMinValue() > ConvertedRHS.getMaxValue())) {
+return getTrueRange(T);

steakhal wrote:
> This and the subsequent similar block could be implemented by a member 
> function of a `RangeSet`.
> It's highly likely that many of these `VisitBinaryOperator()` functions 
> could benefit from reusing them in the future if we decide to handle more of 
> them.
I agree. I will try to find similarities which can be extracted from remaining 
binops and put them I a member function.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-04-07 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 421122.
manas added a comment.

Fix comments and rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,59 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, unsigned int u3,
+int s1, int s2, int s3) {
+
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval(s1 != s2); // expected-warning{{TRUE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for comparison between different types
+  // Using different variables as previous constraints may interfere in the
+  // reasoning.
+  if (u3 <= 255 && s3 < 0) {
+// u3: [0, 255], s3: [INT_MIN, -1]
+clang_analyzer_eval(u3 != s3); // expected-warning{{TRUE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -20,8 +20,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -1136,18 +1136,7 @@
   }
 
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
-   RangeSet RHS, QualType T) {
-switch (Op) {
-case BO_Or:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_And:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_Rem:
-  return VisitBinaryOperator(LHS, RHS, T);
-default:
-  return infer(T);
-}
-  }
+   RangeSet RHS, QualType T);
 
   //===--===//
   // Ranges and operators
@@ -1412,6 +1401,49 @@
 //   Range-based reasoning about symbolic operations
 //===--===//
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,
+   RangeSet RHS,
+   QualType T) {
+
+  // We must check for empty RangeSets. This gets done via VisitBinaryOperator
+  // for other operators, but BO_NE is handled specifically.
+  if (LHS.isEmpty() || RHS.isEmpty()) {
+return RangeFactory.getEmptySet();
+  }
+
+  Range CoarseLHS = fillGaps(LHS);
+  Range CoarseRHS = fillGaps(RHS);
+
+  APSIntType ResultType = ValueFactory.getAPSIntType(T);
+
+  auto ConvertedCoarseLHS = convert(CoarseLHS, ResultType);
+  auto ConvertedCoarseRHS = convert(CoarseRHS, ResultType);
+
+  if (!ConvertedCoarseLHS || !ConvertedCoarseRHS) {
+return infer(T);
+  }
+
+  // When both the Ranges are non-overlapping then all possible pairs of (x, y)
+  // in ConvertedLHS, ConvertedRHS respectively, will satisfy expression
+  // (x != y).
+  if ((ConvertedCoarseLHS->To() < Conv

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-04-07 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 421134.
manas added a comment.

Format constant-folding.c


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,59 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, unsigned int u3,
+  int s1, int s2, int s3) {
+
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval(s1 != s2); // expected-warning{{TRUE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for comparison between different types
+  // Using different variables as previous constraints may interfere in the
+  // reasoning.
+  if (u3 <= 255 && s3 < 0) {
+// u3: [0, 255], s3: [INT_MIN, -1]
+clang_analyzer_eval(u3 != s3); // expected-warning{{TRUE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -20,8 +20,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -1136,18 +1136,7 @@
   }
 
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
-   RangeSet RHS, QualType T) {
-switch (Op) {
-case BO_Or:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_And:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_Rem:
-  return VisitBinaryOperator(LHS, RHS, T);
-default:
-  return infer(T);
-}
-  }
+   RangeSet RHS, QualType T);
 
   //===--===//
   // Ranges and operators
@@ -1412,6 +1401,49 @@
 //   Range-based reasoning about symbolic operations
 //===--===//
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,
+   RangeSet RHS,
+   QualType T) {
+
+  // We must check for empty RangeSets. This gets done via VisitBinaryOperator
+  // for other operators, but BO_NE is handled specifically.
+  if (LHS.isEmpty() || RHS.isEmpty()) {
+return RangeFactory.getEmptySet();
+  }
+
+  Range CoarseLHS = fillGaps(LHS);
+  Range CoarseRHS = fillGaps(RHS);
+
+  APSIntType ResultType = ValueFactory.getAPSIntType(T);
+
+  auto ConvertedCoarseLHS = convert(CoarseLHS, ResultType);
+  auto ConvertedCoarseRHS = convert(CoarseRHS, ResultType);
+
+  if (!ConvertedCoarseLHS || !ConvertedCoarseRHS) {
+return infer(T);
+  }
+
+  // When both the Ranges are non-overlapping then all possible pairs of (x, y)
+  // in ConvertedLHS, ConvertedRHS respectively, will satisfy expression
+  // (x != y).
+  if ((Convert

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-07-11 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

I was busy with other stuff. I will take a look at it now.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-07-15 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 444911.
manas added a comment.

Add concrete tests for same and different types


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,71 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, unsigned int u3,
+  int s1, int s2, int s3) {
+
+  // Checks for concrete value with same type
+  if (u1 > 1 && u1 < 3 && u2 > 1 && u2 < 3) {
+// u1: [2, 2], u2: [2, 2]
+clang_analyzer_eval(u1 != u2); // expected-warning{{FALSE}}
+  }
+
+  // Check for concrete value with different types
+  if (u1 > 4 && u1 < 6 && s1 > 4 && s1 < 6) {
+// u1: [5, 5], s1: [5, 5]
+clang_analyzer_eval(u1 != s1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval(s1 != s2); // expected-warning{{TRUE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for comparison between different types
+  // Using different variables as previous constraints may interfere in the
+  // reasoning.
+  if (u3 <= 255 && s3 < 0) {
+// u3: [0, 255], s3: [INT_MIN, -1]
+clang_analyzer_eval(u3 != s3); // expected-warning{{TRUE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -1326,18 +1326,7 @@
   }
 
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
-   RangeSet RHS, QualType T) {
-switch (Op) {
-case BO_Or:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_And:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_Rem:
-  return VisitBinaryOperator(LHS, RHS, T);
-default:
-  return infer(T);
-}
-  }
+   RangeSet RHS, QualType T);
 
   //===--===//
   // Ranges and operators
@@ -1607,6 +1596,49 @@
 //   Range-based reasoning about symbolic operations
 //===--===//
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,
+   RangeSet RHS,
+   QualType T) {
+
+  // We must check for empty RangeSets. This gets done via VisitBinaryOperator
+  // for other operators, but BO_NE is handled specifically.
+  if (LHS.isEmpty() || RHS.isEmpty()) {
+return RangeFactory.getEmptySet();
+  }
+
+  Range CoarseLHS = fillGaps(LHS);
+  Range CoarseRHS = fillGaps(RHS);
+
+  APSIntType ResultType = ValueFactory.getAPSIntType(T);
+
+  auto ConvertedCoarseLHS = convert(CoarseLHS, ResultType);
+  auto ConvertedCoarseRHS = convert(CoarseRHS, ResultType);
+
+  if (!ConvertedCoarseLHS || !ConvertedCoarseRHS) {
+return infer(T);
+  }
+
+  // When both the Ranges are non-overlapping then all possible pairs of (x

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-07-15 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

The coverage showing unreachability of `VisitBinaryOperator` for 
concrete integer cases. F23801808: RangeConstraintManager.cpp.html 





Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1415-1416
+
+  Range CoarseLHS = fillGaps(LHS);
+  Range CoarseRHS = fillGaps(RHS);
+

ASDenysPetrov wrote:
> Avoid filling the gaps, because it's completely possible to compare all the 
> ranges.
> E.g. //LHS //`[1,2]U[8,9]`  and  //RHS //`[5,6]` are not equal.
> And you don't need to fiil the gap in LHS, because it will lead you to a 
> wrong answer, like `[1,9] != [5,6]` => **UNKNOWN** instead of **TRUE**.
If we don't fill gaps, then we will be making this method O(n) instead of O(1) 
as of now. As I see it, filling RHS (and not filling LHS), it can iterate over 
all ranges in LHS, and check each range's intersection with CoarseRHS.

Before, I do this, I just wanted to point out the unreachability of concrete 
cases to this method. I have tried to explain this below.



Comment at: clang/test/Analysis/constant-folding.c:339
+  }
+}

ASDenysPetrov wrote:
> I'd like to see the cases with concrete integers as well.
I have checked the coverage reports which show that concrete values are not 
reaching `VisitBinaryOperator`. This is due to them being trivially 
inferred in `RangedConstraintManager.cpp`. I attached the coverage for 
`RangeConstraintManager.cpp`.

I think that I should remove the handling of concrete APSInt all together from 
SymbolicRangeInferrer for above reason. What do you guys think?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-07-18 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 445549.
manas added a comment.

Remove filling gaps and convert, use castTo, and add tests for short-ushort,
char-uchar pairs


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,111 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, unsigned int u3,
+  int s1, int s2, int s3, unsigned char uch,
+  signed char sch, short ssh, unsigned short ush) {
+
+  // Check when RHS is in between two Ranges in LHS
+  if (((u1 >= 1 && u1 <= 2) || (u1 >= 8 && u1 <= 9)) &&
+  u2 >= 5 && u2 <= 6) {
+// u1: [1, 2]U[8, 9], u2: [5, 6]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  // Checks for concrete value with same type
+  if (u1 > 1 && u1 < 3 && u2 > 1 && u2 < 3) {
+// u1: [2, 2], u2: [2, 2]
+clang_analyzer_eval(u1 != u2); // expected-warning{{FALSE}}
+  }
+
+  // Check for concrete value with different types
+  if (u1 > 4 && u1 < 6 && s1 > 4 && s1 < 6) {
+// u1: [5, 5], s1: [5, 5]
+clang_analyzer_eval(u1 != s1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval(s1 != s2); // expected-warning{{TRUE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for comparison between different types
+  // Using different variables as previous constraints may interfere in the
+  // reasoning.
+  if (u3 <= 255 && s3 < 0) {
+// u3: [0, 255], s3: [INT_MIN, -1]
+clang_analyzer_eval(u3 != s3); // expected-warning{{TRUE}}
+  }
+
+  // Checks for char-uchar types
+  if (uch >= 1 && sch <= 1) {
+// uch: [1, UCHAR_MAX], sch: [SCHAR_MIN, 1]
+clang_analyzer_eval(uch != sch); // expected-warning{{UNKNOWN}}
+  }
+
+  if (uch > 1 && sch < 1) {
+// uch: [2, CHAR_MAX], sch: [SCHAR_MIN, 0]
+clang_analyzer_eval(uch != sch); // expected-warning{{TRUE}}
+  }
+
+  if (uch <= 1 && uch >= 1 && sch <= 1 && sch >= 1) {
+// uch: [1, 1], sch: [1, 1]
+clang_analyzer_eval(uch != sch); // expected-warning{{FALSE}}
+  }
+
+  // Checks for short-ushort types
+  if (ush >= 1 && ssh <= 1) {
+// ush: [1, USHRT_MAX], ssh: [SHRT_MIN, 1]
+clang_analyzer_eval(ush != ssh); // expected-warning{{UNKNOWN}}
+  }
+
+  if (ush > 1 && ssh < 1) {
+// ush: [2, USHRT_MAX], ssh: [SHRT_MIN, 0]
+clang_analyzer_eval(ush != ssh); // expected-warning{{TRUE}}
+  }
+
+  if (ush <= 1 && ush >= 1 && ssh <= 1 && ssh >= 1) {
+// ush: [1, 1], ssh: [1, 1]
+clang_analyzer_eval(ush != ssh); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -1333,18 +1333,7 @@
   }
 
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
-   RangeSet RHS, QualType T) {
-switch (Op) {
-case BO_Or:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_And:
-  return V

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-07-18 Thread Manas Gupta via Phabricator via cfe-commits
manas marked 5 inline comments as done.
manas added a comment.

Considering @ASDenysPetrov 's example of `LHS = [1, 2] U [8, 9]` and `RHS = [5, 
6]`, I constructed a test case as following:

`(((u1 >= 1 && u1 <= 2) || (u1 >= 8 && u1 <= 9)) && u2 >= 5 && u2 <= 6)`

but I can see that the analyzer is bifurcating paths at the OR operator. 
Essentially, there are two diverged paths:

1. `1 <= u1 && u1 <= 2 && 5 <= u2 && u2 <= 6`

2. `8 <= u1 && u1 <= 9 && 5 <= u2 && u2 <= 6`

Separately, they hit `VisitBinaryOperator` and in both cases, we get 
`TRUE` for `(u1 != u2)`.

Is there any other way to formulate the expression so that it constructs `LHS = 
[1, 2] U [8, 9]`?




Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1420-1421
+
+  auto ConvertedCoarseLHS = convert(CoarseLHS, ResultType);
+  auto ConvertedCoarseRHS = convert(CoarseRHS, ResultType);
+

ASDenysPetrov wrote:
> The `ResultType` of `BO_NE` is `bool`. You don't need to convert your 
> **integer **ranges to **boolean**. Otherwise, you'll lose the information to 
> compare. 
I have utilized castTo method for conversion of different types so that they 
can be compared/intersected.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1437-1441
+  if (ConvertedCoarseLHS->getConcreteValue() &&
+  ConvertedCoarseLHS->getConcreteValue() ==
+  ConvertedCoarseRHS->getConcreteValue()) {
+return getFalseRange(T);
+  }

ASDenysPetrov wrote:
> This is OK but check `ConvertedCoarseRHS->getConcreteValue()` for `nullptr` 
> before getting the value.
> 
I have removed the concrete case handling as it was unreachable.



Comment at: clang/test/Analysis/constant-folding.c:289
+
+  // Check when RHS is in between two Ranges in LHS
+  if (((u1 >= 1 && u1 <= 2) || (u1 >= 8 && u1 <= 9)) &&

@ASDenysPetrov I have used your example, but I realized that the path 
bifurcates and sizeof `LHS` RangeSet is always 1 inside 
`VisitBinaryOperator`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-07-18 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 445671.
manas added a comment.

Rebase and fix comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,111 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, unsigned int u3,
+  int s1, int s2, int s3, unsigned char uch,
+  signed char sch, short ssh, unsigned short ush) {
+
+  // Check when RHS is in between two Ranges in LHS
+  if (((u1 >= 1 && u1 <= 2) || (u1 >= 8 && u1 <= 9)) &&
+  u2 >= 5 && u2 <= 6) {
+// u1: [1, 2]U[8, 9], u2: [5, 6]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  // Checks for concrete value with same type
+  if (u1 > 1 && u1 < 3 && u2 > 1 && u2 < 3) {
+// u1: [2, 2], u2: [2, 2]
+clang_analyzer_eval(u1 != u2); // expected-warning{{FALSE}}
+  }
+
+  // Check for concrete value with different types
+  if (u1 > 4 && u1 < 6 && s1 > 4 && s1 < 6) {
+// u1: [5, 5], s1: [5, 5]
+clang_analyzer_eval(u1 != s1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval(s1 != s2); // expected-warning{{TRUE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 >= -750 && s2 <= -500) {
+// s1: [-1000,-500], s2: [-750, -500]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for comparison between different types
+  // Using different variables as previous constraints may interfere in the
+  // reasoning.
+  if (u3 <= 255 && s3 < 0) {
+// u3: [0, 255], s3: [INT_MIN, -1]
+clang_analyzer_eval(u3 != s3); // expected-warning{{TRUE}}
+  }
+
+  // Checks for char-uchar types
+  if (uch >= 1 && sch <= 1) {
+// uch: [1, UCHAR_MAX], sch: [SCHAR_MIN, 1]
+clang_analyzer_eval(uch != sch); // expected-warning{{UNKNOWN}}
+  }
+
+  if (uch > 1 && sch < 1) {
+// uch: [2, CHAR_MAX], sch: [SCHAR_MIN, 0]
+clang_analyzer_eval(uch != sch); // expected-warning{{TRUE}}
+  }
+
+  if (uch <= 1 && uch >= 1 && sch <= 1 && sch >= 1) {
+// uch: [1, 1], sch: [1, 1]
+clang_analyzer_eval(uch != sch); // expected-warning{{FALSE}}
+  }
+
+  // Checks for short-ushort types
+  if (ush >= 1 && ssh <= 1) {
+// ush: [1, USHRT_MAX], ssh: [SHRT_MIN, 1]
+clang_analyzer_eval(ush != ssh); // expected-warning{{UNKNOWN}}
+  }
+
+  if (ush > 1 && ssh < 1) {
+// ush: [2, USHRT_MAX], ssh: [SHRT_MIN, 0]
+clang_analyzer_eval(ush != ssh); // expected-warning{{TRUE}}
+  }
+
+  if (ush <= 1 && ush >= 1 && ssh <= 1 && ssh >= 1) {
+// ush: [1, 1], ssh: [1, 1]
+clang_analyzer_eval(ush != ssh); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -1333,18 +1333,7 @@
   }
 
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
-   RangeSet RHS, QualType T) {
-switch (Op) {
-case BO_Or:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_And:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_Rem:
-  return Visi

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-07-18 Thread Manas Gupta via Phabricator via cfe-commits
manas marked an inline comment as done.
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1272-1273
+  // (x != y).
+  if ((ConvertedLHS.getMaxValue() < ConvertedRHS.getMinValue()) ||
+  (ConvertedLHS.getMinValue() > ConvertedRHS.getMaxValue())) {
+return getTrueRange(T);

manas wrote:
> steakhal wrote:
> > This and the subsequent similar block could be implemented by a member 
> > function of a `RangeSet`.
> > It's highly likely that many of these `VisitBinaryOperator()` functions 
> > could benefit from reusing them in the future if we decide to handle more 
> > of them.
> I agree. I will try to find similarities which can be extracted from 
> remaining binops and put them I a member function.
This comment is about finding intersecting Ranges in 
`ConvertedLHS/ConvertedRHS` which was previously done by comparing 
`getMinValue/getMaxValue`. Now, we use intersect family of methods for it.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-01 Thread Manas Gupta via Phabricator via cfe-commits
manas created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: teemperor.
manas requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Add test cases for symbolic addition operator.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D103440

Files:
  clang/test/Analysis/constant-folding.c


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,57 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for overflows
+  if (a >= INT_MAX) {
+clang_analyzer_eval((a + 0) >= 0); // expected-warning{{TRUE}}
+
+if (a > INT_MAX) {
+  clang_analyzer_eval((a + b) <= 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) > 0); // expected-warning{{FALSE}}
+}
+  }
+
+  // Both operands are positive
+  if (a >= 0 && b >= 0) {
+clang_analyzer_eval((a + b) < 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) < UINT_MAX); // expected-warning{{UNKNOWN}}
+
+if (a <= UINT_MAX && b <= UINT_MAX) {
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{UNKNOWN}}
+}
+  }
+
+  // Checks for unsigned ints
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed ints
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+
+if (c > INT_MIN) {
+  clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((c + d) == INT_MAX<<1); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for positive ints
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) != 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) < 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges
+  if (a >= 0 && a <= 10 && b >= -20 && b <= 20) {
+clang_analyzer_eval((a + b) >= -20); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) <= 30); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) == -20); // expected-warning{{TRUE}}
+  }
+}


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,57 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for overflows
+  if (a >= INT_MAX) {
+clang_analyzer_eval((a + 0) >= 0); // expected-warning{{TRUE}}
+
+if (a > INT_MAX) {
+  clang_analyzer_eval((a + b) <= 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) > 0); // expected-warning{{FALSE}}
+}
+  }
+
+  // Both operands are positive
+  if (a >= 0 && b >= 0) {
+clang_analyzer_eval((a + b) < 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) < UINT_MAX); // expected-warning{{UNKNOWN}}
+
+if (a <= UINT_MAX && b <= UINT_MAX) {
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{UNKNOWN}}
+}
+  }
+
+  // Checks for unsigned ints
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed ints
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+
+if (c > INT_MIN) {
+  clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((c + d) == INT_MAX<<1); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for positive ints
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) != 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) < 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges
+  if (a >= 0 && a <= 10 && b >= -20 && b <= 20) {
+clang_analyzer_eval((a + b) >= -20); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) <= 30); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) == -20); // expected-warning{{TRUE}}
+  }
+}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-01 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

@NoQ I figured out the tests but while testing against Z3, I mixed up 
constraints. I am changing those.




Comment at: clang/test/Analysis/constant-folding.c:265
+if (a > INT_MAX) {
+  clang_analyzer_eval((a + b) <= 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) > 0); // expected-warning{{FALSE}}

xazax.hun wrote:
> Since both `a` and `b` are unsigned values, their sum is also unsigned. We 
> basically check if their sum could be zero. I don't see why it could not in 
> this case (e.g. when `b == UINT_MAX - a + 1`). Do I miss something?
I am editing that condition to be `b >= INT_MAX`.



Comment at: clang/test/Analysis/constant-folding.c:275
+
+if (a <= UINT_MAX && b <= UINT_MAX) {
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{UNKNOWN}}

xazax.hun wrote:
> vsavchenko wrote:
> > I think this is always true.
> So is `a >= 0 && b >= 0` unless I miss something.
@vsavchenko true, I am removing that conditional as it serves no purpose there.

@xazax.hun that's true.



Comment at: clang/test/Analysis/constant-folding.c:282
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{FALSE}}
+  }

xazax.hun wrote:
> I think `UINT_MAX + UINT_MAX` supposed to be positive. Do I miss something 
> here?
Should not `UINT_MAX + UINT_MAX` wrap around to be negative? I think I 
misunderstood it.



Comment at: clang/test/Analysis/constant-folding.c:290-291
+if (c > INT_MIN) {
+  clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((c + d) == INT_MAX<<1); // expected-warning{{TRUE}}
+}

vsavchenko wrote:
> Here is the same note, `clang_analyzer_eval` doesn't produce `TRUE` only 
> because this condition might be true.
understood.



Comment at: clang/test/Analysis/constant-folding.c:298
+clang_analyzer_eval((c + d) != 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) < 0); // expected-warning{{TRUE}}
+  }

vsavchenko wrote:
> If `c == d == 1` this doesn't hold. Did you want to check here that we 
> account for overflows?
Yes, I was checking for that. I am changing that case.



Comment at: clang/test/Analysis/constant-folding.c:302
+  // Checks for inclusive ranges
+  if (a >= 0 && a <= 10 && b >= -20 && b <= 20) {
+clang_analyzer_eval((a + b) >= -20); // expected-warning{{TRUE}}

vsavchenko wrote:
> What about other cases here? I mean specifically when two ranges are have a 
> form `[A, B]`
I am adding more cases here.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-01 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/test/Analysis/constant-folding.c:282
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{FALSE}}
+  }

manas wrote:
> xazax.hun wrote:
> > I think `UINT_MAX + UINT_MAX` supposed to be positive. Do I miss something 
> > here?
> Should not `UINT_MAX + UINT_MAX` wrap around to be negative? I think I 
> misunderstood it.
Understood. My bad.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-02 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 349225.
manas added a comment.

Fixed test cases expecting wrong assertions and added few more test cases.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/test/Analysis/constant-folding.c


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,57 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) < 0); // expected-warning{{UNKNOWN}}
+
+if (c == INT_MIN && d == INT_MIN) {
+  clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+}
+
+if (c >= -20 && d >= -40) {
+  clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) > 1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+  }
+}


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,57 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) < 0); // expected-warning{{UNKNOWN}}
+
+if (c == INT_MIN && d == INT_MIN) {
+  clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+}
+
+if (c >= -20 && d >= -40) {
+  clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) > 1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+  }
+}
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-09-24 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

I haven't tried specializing that `VisitBinaryOperator` method which converts 
Ranges from RangeSets (as @vsavchenko mentioned). Should this case for NE stay 
here in the switch or move?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-09-24 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 374746.
manas added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -466,3 +466,41 @@
 clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
   }
 }
+
+void testEqualityRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when ranges are not overlapping
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (a >= 20 && a <= 50 && b >= 20 && b <= 50) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -20 && c <= 20 && d >= -20 && d <= 20) {
+clang_analyzer_eval((c != d) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (a >= 100 && a <= 200 && b >= 150 && b <= 300) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -80 && c <= -50 && d >= -100 && d <= -75) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (a >= 500 && a <= 1000 && b >= 750 && b <= 1000) {
+clang_analyzer_eval((a != b) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -1000 && c <= -500 && d <= -500 && d >= -750) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{UNKNOWN}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -956,6 +956,8 @@
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
RangeSet RHS, QualType T) {
 switch (Op) {
+case BO_NE:
+  return VisitBinaryOperator(LHS, RHS, T);
 case BO_Or:
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_And:
@@ -1226,6 +1228,27 @@
 //   Range-based reasoning about symbolic operations
 
//===--===//
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS, Range 
RHS,
+   QualType T) {
+
+  // When both the ranges are non-overlapping then all possible pairs of (x, y)
+  // in LHS, RHS will satisfy expression (x != y)
+  if ((LHS.To() < RHS.From()) || (RHS.To() < LHS.From())) {
+return getTrueRange(T);
+  }
+
+  // If both ranges contain only one same Point then the expression will always
+  // return true
+  if ((LHS.From() == RHS.To()) && (LHS.To() == RHS.To()) &&
+  (LHS.From() == RHS.From())) {
+return getFalseRange(T);
+  }
+
+  // In all other cases, the resulting range cannot be deduced.
+  return RangeFactory.getEmptySet();
+}
+
 template <>
 RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS, Range 
RHS,
QualType T) {


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -466,3 +466,41 @@
 clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
   }
 }
+
+void testEqualityRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when ranges are not overlapping
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (a >= 20 && a <= 50 && b >= 20 && b <= 50) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -20 && c <= 20 && d >= -20 && d <= 20) {
+clang_analyzer_eval((c != d) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (a >= 100 && a <= 200 && b >= 150 && b <= 300) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -80 && c <= -50 && d >= -100 && d <= -75) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (a >= 

[PATCH] D106416: [analyzer] Fix build dependency issues for SATest

2021-09-25 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 375017.
manas added a comment.

Upgrade cmake to 3.21.3


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106416/new/

https://reviews.llvm.org/D106416

Files:
  clang/utils/analyzer/Dockerfile


Index: clang/utils/analyzer/Dockerfile
===
--- clang/utils/analyzer/Dockerfile
+++ clang/utils/analyzer/Dockerfile
@@ -17,8 +17,9 @@
 gettext=0.19.8.1* \
 python3=3.6.7-1~18.04 \
 python3-pip=9.0.1-2.3* \
-cmake=3.20.5* \
-ninja-build=1.8.2-1
+cmake=3.21.3* \
+ninja-build=1.8.2-1 \
+ccache=3.4*
 
 # box2d dependencies
 RUN apt-get install -y \


Index: clang/utils/analyzer/Dockerfile
===
--- clang/utils/analyzer/Dockerfile
+++ clang/utils/analyzer/Dockerfile
@@ -17,8 +17,9 @@
 gettext=0.19.8.1* \
 python3=3.6.7-1~18.04 \
 python3-pip=9.0.1-2.3* \
-cmake=3.20.5* \
-ninja-build=1.8.2-1
+cmake=3.21.3* \
+ninja-build=1.8.2-1 \
+ccache=3.4*
 
 # box2d dependencies
 RUN apt-get install -y \
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106416: [analyzer] Fix build dependency issues for SATest

2021-09-25 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

@vsavchenko should we land this?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106416/new/

https://reviews.llvm.org/D106416

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-09-28 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 375682.
manas added a comment.

Move method to a specialized template for VisitBinaryOperator


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -466,3 +466,41 @@
 clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
   }
 }
+
+void testEqualityRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when ranges are not overlapping
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (a >= 20 && a <= 50 && b >= 20 && b <= 50) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -20 && c <= 20 && d >= -20 && d <= 20) {
+clang_analyzer_eval((c != d) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (a >= 100 && a <= 200 && b >= 150 && b <= 300) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -80 && c <= -50 && d >= -100 && d <= -75) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (a >= 500 && a <= 1000 && b >= 750 && b <= 1000) {
+clang_analyzer_eval((a != b) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -1000 && c <= -500 && d <= -500 && d >= -750) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{UNKNOWN}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -21,8 +21,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -956,6 +956,8 @@
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
RangeSet RHS, QualType T) {
 switch (Op) {
+case BO_NE:
+  return VisitBinaryOperator(LHS, RHS, T);
 case BO_Or:
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_And:
@@ -1029,6 +1031,27 @@
 return infer(T);
   }
 
+  template <>
+  RangeSet VisitBinaryOperator(RangeSet LHS, RangeSet RHS, QualType T) {
+// When both the RangeSets are non-overlapping then all possible pairs of
+// (x, y) in LHS, RHS respectively, will satisfy expression (x != y).
+if ((LHS.getMaxValue() < RHS.getMinValue()) ||
+(LHS.getMinValue() > RHS.getMaxValue())) {
+  return getTrueRange(T);
+}
+
+// If both RangeSets contain only one Point which is equal then the
+// expression will always return true.
+if ((LHS.getMinValue() == RHS.getMaxValue()) &&
+(LHS.getMaxValue() == RHS.getMaxValue()) &&
+(LHS.getMinValue() == RHS.getMinValue())) {
+  return getFalseRange(T);
+}
+
+// In all other cases, the resulting range cannot be deduced.
+return infer(T);
+  }
+
   /// Return a symmetrical range for the given range and type.
   ///
   /// If T is signed, return the smallest range [-x..x] that covers the 
original


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -466,3 +466,41 @@
 clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
   }
 }
+
+void testEqualityRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when ranges are not overlapping
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (a >= 20 && a <= 50 && b >= 20 && b <= 50) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -20 && c <= 20 && d >= -20 && d <= 20) {
+clang_analyzer_eval((c != d) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (a >= 100 && a <= 200 && b >= 15

[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-09-28 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 375689.
manas added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -466,3 +466,41 @@
 clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
   }
 }
+
+void testEqualityRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when ranges are not overlapping
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (a >= 20 && a <= 50 && b >= 20 && b <= 50) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -20 && c <= 20 && d >= -20 && d <= 20) {
+clang_analyzer_eval((c != d) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (a >= 100 && a <= 200 && b >= 150 && b <= 300) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -80 && c <= -50 && d >= -100 && d <= -75) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (a >= 500 && a <= 1000 && b >= 750 && b <= 1000) {
+clang_analyzer_eval((a != b) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -1000 && c <= -500 && d <= -500 && d >= -750) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{UNKNOWN}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -21,8 +21,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -956,6 +956,8 @@
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
RangeSet RHS, QualType T) {
 switch (Op) {
+case BO_NE:
+  return VisitBinaryOperator(LHS, RHS, T);
 case BO_Or:
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_And:
@@ -1029,6 +1031,27 @@
 return infer(T);
   }
 
+  template <>
+  RangeSet VisitBinaryOperator(RangeSet LHS, RangeSet RHS, QualType T) {
+// When both the RangeSets are non-overlapping then all possible pairs of
+// (x, y) in LHS, RHS respectively, will satisfy expression (x != y).
+if ((LHS.getMaxValue() < RHS.getMinValue()) ||
+(LHS.getMinValue() > RHS.getMaxValue())) {
+  return getTrueRange(T);
+}
+
+// If both RangeSets contain only one Point which is equal then the
+// expression will always return true.
+if ((LHS.getMinValue() == RHS.getMaxValue()) &&
+(LHS.getMaxValue() == RHS.getMaxValue()) &&
+(LHS.getMinValue() == RHS.getMinValue())) {
+  return getFalseRange(T);
+}
+
+// In all other cases, the resulting range cannot be deduced.
+return infer(T);
+  }
+
   /// Return a symmetrical range for the given range and type.
   ///
   /// If T is signed, return the smallest range [-x..x] that covers the 
original


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -466,3 +466,41 @@
 clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
   }
 }
+
+void testEqualityRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when ranges are not overlapping
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (a >= 20 && a <= 50 && b >= 20 && b <= 50) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= -20 && c <= 20 && d >= -20 && d <= 20) {
+clang_analyzer_eval((c != d) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (a >= 100 && a <= 200 && b >= 150 && b <= 300) {
+clang_analyzer_eval((a != b) != 0

[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-09-28 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

The pre-merge checks fail due to the patch being unable to get applied. The 
troubleshooting 

 suggest to update the patch via `arc diff ```git merge-base HEAD origin``` 
--update D106102` and it would include all local changes into that patch. 
Shouldn't I avoid including all local changes, as some local changes are still 
WIP?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-09-29 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D106102#3029633 , @martong wrote:

> In D106102#3028584 , @manas wrote:
>
>> The pre-merge checks fail due to the patch being unable to get applied. The 
>> troubleshooting 
>> 
>>  suggest to update the patch via `arc diff ```git merge-base HEAD origin``` 
>> --update D106102` and it would include all local changes into that patch. 
>> Shouldn't I avoid including all local changes, as some local changes are 
>> still WIP?
>
> I guess `HEAD` should refer to the commit that represents this patch, in this 
> case that is `ce82443c69be`. And I believe you local changes that are not 
> committed should not affect `arc diff` at all. But, as a precaution, you 
> could first stash your local changes before calling `arc`. Hope this helps.

Thanks. That was helpful.




Comment at: clang/test/Analysis/constant-folding.c:470
+
+void testEqualityRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when ranges are not overlapping

steakhal wrote:
> steakhal wrote:
> > 
> I would prefer `u1`, `u2`, `s1`, `s2` respectively.
> This way the name would signify the signess of the variable.
Makes sense. I have amended it.



Comment at: clang/test/Analysis/constant-folding.c:473
+  if (a <= 10 && b >= 20) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{TRUE}}
+  }

steakhal wrote:
> Isn't  `a != b` enough? Why do you need the `(..) != 0` part?
Sometime ago, Valeriy and I were discussing about how solver can't reason about 
sub-expressions containing logical operators with ranges. Currently, only 
`==/!=` operators can reason about them, as they are trivial. So, this case is 
for `!=` operator used with sub-expressions.



Comment at: clang/test/Analysis/constant-folding.c:476-478
+  if (c <= INT_MIN + 10 && d >= INT_MAX - 10) {
+clang_analyzer_eval((c != d) == 0); // expected-warning{{FALSE}}
+  }

steakhal wrote:
> How is this different compared to the previous case? The difference I can see 
> is that now we use different constants and the `==` operator in the outer 
> expression. None of which should really change the behavior AFAICT.
I wanted to put a signed case. Although I believe, I should have replaced `==` 
with `!=`.



Comment at: clang/test/Analysis/constant-folding.c:481
+  // Checks when ranges are completely overlapping and have more than one point
+  if (a >= 20 && a <= 50 && b >= 20 && b <= 50) {
+clang_analyzer_eval((a != b) != 0); // expected-warning{{UNKNOWN}}

steakhal wrote:
> You could have a comment that `a: [20,50]  b:[20,50]`.
> It would be easier to comprehend than the chain of conjunctions.
> Similarly, how at L464 does.
Sure. I have amended.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-09-29 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 376035.
manas added a comment.

Apply mentioned edits in testcases


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -466,3 +466,49 @@
 clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, int s1, int s2) {
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MIN - 10,INT_MAX]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval((s1 != s2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval((u1 != u2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -21,8 +21,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -956,6 +956,8 @@
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
RangeSet RHS, QualType T) {
 switch (Op) {
+case BO_NE:
+  return VisitBinaryOperator(LHS, RHS, T);
 case BO_Or:
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_And:
@@ -1029,6 +1031,27 @@
 return infer(T);
   }
 
+  template <>
+  RangeSet VisitBinaryOperator(RangeSet LHS, RangeSet RHS, QualType T) {
+// When both the RangeSets are non-overlapping then all possible pairs of
+// (x, y) in LHS, RHS respectively, will satisfy expression (x != y).
+if ((LHS.getMaxValue() < RHS.getMinValue()) ||
+(LHS.getMinValue() > RHS.getMaxValue())) {
+  return getTrueRange(T);
+}
+
+// If both RangeSets contain only one Point which is equal then the
+// expression will always return true.
+if ((LHS.getMinValue() == RHS.getMaxValue()) &&
+(LHS.getMaxValue() == RHS.getMaxValue()) &&
+(LHS.getMinValue() == RHS.getMinValue())) {
+  return getFalseRange(T);
+}
+
+// In all other cases, the resulting range cannot be deduced.
+return infer(T);
+  }
+
   /// Return a symmetrical range for the given range and type.
   ///
   /// If T is signed, return the smallest range [-x..x] that covers the original
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-09-30 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D106102#3032888 , @steakhal wrote:

> Okay, I don't see any problems besides this typo.

Oops!

> BTW do you plan to implement other rules besides this in the future?
> E.g. we currently miss this:
> 'x < y' is `true` if `max(x) < min(y)`; and `false` if `min(x) >= max(y)`
> 'x > y', 'x <= y', etc. in a similar way.

I think these cases need to be specialized as well. As, they aren't returning 
some complex RangeSet, so we can get away with a specialized template for 
`BO_LT/BO_GT` etc., instead of a class method (like `BO_Rem` has). I can work 
on this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-09-30 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 376363.
manas added a comment.

Fix typo


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,49 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, int s1, int s2) {
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval((s1 != s2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval((u1 != u2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -20,8 +20,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -955,6 +955,8 @@
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
RangeSet RHS, QualType T) {
 switch (Op) {
+case BO_NE:
+  return VisitBinaryOperator(LHS, RHS, T);
 case BO_Or:
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_And:
@@ -1024,6 +1026,27 @@
 return infer(T);
   }
 
+  template <>
+  RangeSet VisitBinaryOperator(RangeSet LHS, RangeSet RHS, QualType T) {
+// When both the RangeSets are non-overlapping then all possible pairs of
+// (x, y) in LHS, RHS respectively, will satisfy expression (x != y).
+if ((LHS.getMaxValue() < RHS.getMinValue()) ||
+(LHS.getMinValue() > RHS.getMaxValue())) {
+  return getTrueRange(T);
+}
+
+// If both RangeSets contain only one Point which is equal then the
+// expression will always return true.
+if ((LHS.getMinValue() == RHS.getMaxValue()) &&
+(LHS.getMaxValue() == RHS.getMaxValue()) &&
+(LHS.getMinValue() == RHS.getMinValue())) {
+  return getFalseRange(T);
+}
+
+// In all other cases, the resulting range cannot be deduced.
+return infer(T);
+  }
+
   /// Return a symmetrical range for the given range and type.
   ///
   /// If T is signed, return the smallest range [-x..x] that covers the original
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-10-01 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D106102#3035598 , @steakhal wrote:

> Good work. Land it.

I do not have landing rights.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D107312: [analyzer] Fix deprecated plistlib functions

2021-10-01 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

Gentle ping.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D107312/new/

https://reviews.llvm.org/D107312

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-10-01 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D106102#3036474 , @steakhal wrote:

> In D106102#3036220 , @manas wrote:
>
>> I do not have landing rights.
>
> Please add your name and email on whom behalf I should commit this patch. 
> Mine is `Balazs Benics`

It is `Manas `

Thanks!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D107312: [analyzer] Fix deprecated plistlib functions

2021-10-01 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D107312#3036421 , @steakhal wrote:

> I'm not using this script. I'm assuming you run it and verified that it works.
> Thanks for cleaning this up.

I have run it. It is working.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D107312/new/

https://reviews.llvm.org/D107312

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106102: [analyzer][solver] Introduce reasoning for not equal to operator

2021-10-01 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

I'll take a look at this over the weekend.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106102/new/

https://reviews.llvm.org/D106102

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-03 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

> I also would like to see tests where the ranges are not going all the way to 
> either INT_MIN or INT_MAX (if we talk about int), but overflow still might 
> happen, and cases where overflow might happen, but we still can identify the 
> overflowing results precisely (e.g. the result is `[INT_MIN, INT_MIN + 10] 
> and [INT_MAX - 5, INT_MAX]`)

If I understood correctly, does a case like: `c, d in [INT_MAX/2 - 10, 
INT_MAX/2 + 10]` works? It will produce an overflowing range of `[INT_MIN, 
INT_MIN + 18] U [INT_MAX - 21, INT_MAX]`. I will add that to the test-set, if 
that is so.

For now, I have added tests for residual paths and negations of particular 
values, and edited buggy tests.




Comment at: clang/test/Analysis/constant-folding.c:282
+
+if (c >= -20 && d >= -40) {
+  clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}

vsavchenko wrote:
> Great, it's good to check negative numbers.
> I have one note here.  The fact that we don't have a testing framework and 
> use this approach of inspecting the actual analysis has an interesting 
> implication.
> 
> ```
> if (a == 10) { // here we split path into 2 paths: one where a == 10, and one 
> where a != 10;
>// one goes inside of if, one doesn't
>   . . .
> }
> if (a >= 5) { // here we split into 3 paths: a == 10, a < 5, and a in [5, 9] 
> and [11, INT_MAX] (aka a >= 5 and a != 10).
>   // 1 path was infeasible: a == 10 and a < 5
>   // Two of these paths go inside of the if, one doesn't
>   . . .
>   clang_analyzer_eval(a == 10); // it will produce two results: TRUE and FALSE
> }
> clang_analyzer_eval(a == 10); // it will produce three results: TRUE, FALSE, 
> and FALSE
> ```
> 
> We don't want to test how path splitting works in these particular tests 
> (they are about solver and constant folding after all), that's why we try to 
> have only one path going through each `clang_analyzer_eval(...)`
> 
> In this example, you still have residual paths where `c != INT_MIN`, `c == 
> INT_MIN and d != INT_MIN`, and `c == INT_MIN and d == INT_MIN`.
I should add tests for these paths as well so that these can be checked. For 
further cases, I will enforce single path evaluation in test cases (which will 
make it easier to handle here).



Comment at: clang/test/Analysis/constant-folding.c:304-305
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) > 1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+  }

vsavchenko wrote:
> How can these two statements be TRUE at the same time?
Right, my bad. They both should be `UNKNOWN`.

As, `c` and `d` are signed 32-bit positive integers, hence their respective 
values will be in `[1, INT_MAX]`.

When `c == d == 1` then `c + d == 2`, and when `c == d == INT_MAX` then `c + d 
== -2` (overflow). Only possible values which `c + d` **cannot** attain are 
`{-1, 0, 1}`.

As a simple proof:

Dividing this range into 
  R1 = [1, INT_MAX/2] and R2 = [(INT_MAX/2) + 1, INT_MAX]

Now, `c + d` will have 4 combination of ranges to be solved:
- `R1 + R1` : this will never overflow as the maximum value it can attain will 
be `INT_MAX - 1` (when `c == d  == INT_MAX/2`)
- while in `R1 + R2`, `R2 + R1`, and `R2 + R2` expressions will overflow, 
leading value of `c + d` from `INT_MIN` to `-2`, except for case `INT_MAX/2 + 
(INT_MAX/2 + 1)`, where `c + d == INT_MAX`.

Hence, only possible values which can never be attained by `c + d` will be 
`{-1, 0, 1}`. So, the range for our purposes will be `[INT_MIN, -2] U [2, 
INT_MAX]`.

I think I should write tests for `c + d != {-1, 0, 1}` which will make more 
sense here.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-03 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 349749.
manas added a comment.

Added tests for residual paths and negation of certain values, and fixed 
expected warnings for UNKNOWN cases.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/test/Analysis/constant-folding.c


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,71 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) < 0); // expected-warning{{UNKNOWN}}
+
+if (c != INT_MIN) {
+  clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+}
+
+if (c == INT_MIN && d == INT_MIN) {
+  clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+}
+
+if (c == INT_MIN && d != INT_MIN) {
+  clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+}
+
+if (c >= -20 && d >= -40) {
+  clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) > 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) < -1); // expected-warning{{UNKNOWN}}
+  }
+}


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,71 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) < 0); // expected-warning{{UNKNOWN}}
+
+if (c != INT_MIN) {
+  clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+  clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+}
+
+if (c == INT_MIN && d == INT_MIN) {
+  clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+}
+
+if (c == INT_MIN && d != INT_MIN) {
+  clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+}
+
+if (c >= -20 && d >= -40) {
+  clang_analyzer_ev

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-04 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/test/Analysis/constant-folding.c:282
+
+if (c >= -20 && d >= -40) {
+  clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}

vsavchenko wrote:
> manas wrote:
> > vsavchenko wrote:
> > > Great, it's good to check negative numbers.
> > > I have one note here.  The fact that we don't have a testing framework 
> > > and use this approach of inspecting the actual analysis has an 
> > > interesting implication.
> > > 
> > > ```
> > > if (a == 10) { // here we split path into 2 paths: one where a == 10, and 
> > > one where a != 10;
> > >// one goes inside of if, one doesn't
> > >   . . .
> > > }
> > > if (a >= 5) { // here we split into 3 paths: a == 10, a < 5, and a in [5, 
> > > 9] and [11, INT_MAX] (aka a >= 5 and a != 10).
> > >   // 1 path was infeasible: a == 10 and a < 5
> > >   // Two of these paths go inside of the if, one doesn't
> > >   . . .
> > >   clang_analyzer_eval(a == 10); // it will produce two results: TRUE and 
> > > FALSE
> > > }
> > > clang_analyzer_eval(a == 10); // it will produce three results: TRUE, 
> > > FALSE, and FALSE
> > > ```
> > > 
> > > We don't want to test how path splitting works in these particular tests 
> > > (they are about solver and constant folding after all), that's why we try 
> > > to have only one path going through each `clang_analyzer_eval(...)`
> > > 
> > > In this example, you still have residual paths where `c != INT_MIN`, `c 
> > > == INT_MIN and d != INT_MIN`, and `c == INT_MIN and d == INT_MIN`.
> > I should add tests for these paths as well so that these can be checked. 
> > For further cases, I will enforce single path evaluation in test cases 
> > (which will make it easier to handle here).
> In these tests we should really avoid having multiple feasible paths going 
> through one `clang_analyzer_eval`.  We can add `// expected-warning` to it 
> multiple times, but it's harder to understand as a reader of these tests 
> because you need to split all the paths in your mind just like the analyzer 
> does.  It can be useful when testing other features of the analyzer, but here 
> it's not essential.
> 
> And I don't think that you fully understood me.  When multiple paths go 
> through `clang_analyzer_eval`, each of them produces a separate "warning".
> That's why if you want to account for residual paths, you shouldn't add more 
> `if` statements, but add something like:
> ```
> clang_analyzer_eval(a == 10); // expected-warning{{TRUE}}
>   // expected-warning@-1{{TRUE}}
>   // expected-warning@-2{{FALSE}}
> ```
> 
> So, please, instead of writing tests like this, rewrite your test, so that we 
> don't have residual paths.
Understood. I am changing those for single path evaluation accordingly.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-04 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 349796.
manas added a comment.

Fix for cases involving residual paths and add case for overflowing range near 
extremum of a type


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/test/Analysis/constant-folding.c


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,83 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) < 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) > 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) < -1); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // 
expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // 
expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}


Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,83 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) <

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-04 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D103440#2799629 , @xazax.hun wrote:

> I was wondering, if we could try something new with the tests. To increase 
> our confidence that the expected behavior is correct, how about including a 
> Z3 proof with each of the test cases?

We are looking forward to design a unit-test framework for the solver which can 
compact the test cases and make them much more manageable (unlike 
`constant-folding.c`). Perhaps, we can incorporate the Z3 proves in that 
framework, corresponding to test cases.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-05 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D103440#2800710 , @vsavchenko 
wrote:

> In D103440#2800122 , @manas wrote:
>
>> In D103440#2799629 , @xazax.hun 
>> wrote:
>>
>>> I was wondering, if we could try something new with the tests. To increase 
>>> our confidence that the expected behavior is correct, how about including a 
>>> Z3 proof with each of the test cases?
>>
>> We are looking forward to design a unit-test framework for the solver which 
>> can compact the test cases and make them much more manageable (unlike 
>> `constant-folding.c`). Perhaps, we can incorporate the Z3 proves in that 
>> framework, corresponding to test cases.
>
> Hmm, so you mean we can check if the analyzer was compiled with Z3 and if so, 
> verify the same things by it?

Yeah in some sense. But I think that having proof for every test case may 
become redundant for certain cases.

For e.g., consider two test cases for addition operator:

1. c == [0, 10] and d == [-10, 0] will result in (c + d) == [-10, 10]
2. c == d ==  [0, 10] will result in (c + d) == [0, 20]

But the first test case can be modeled as `c - (- d)`or `c - D`, that is,

- usage of subtraction binary operator : (c **-** D), and
- symmetrical inversion of range around origin (**-** d) for symbol `d`. This 
will shift the range from `[-10, 0]` to `[0, 10]`.

Considering having proof for every test case will make the proof for test-case 
1 kind of redundant.

So, I think we should go with @vsavchenko 's method of adding Z3 proof with the 
**implementation** (in code), instead of test cases themselves.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-15 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 352283.
manas edited the summary of this revision.
manas added a comment.
Herald added a subscriber: martong.

Add logic for computing rangeset for an expression containing BO_Add.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,83 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) < 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) > 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) < -1); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -954,6 +954,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Rem:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Add:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -1370,6 +1372,51 @@
   return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)};
 }
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
+Range RHS,
+QualType T) {
+  APSIntType ResultType = ValueFactory.getAPSIntType(T);
+  llvm::APSInt Min = LHS.From() + RHS.From();
+  llvm::APSInt Max = LHS.To() + RHS.To();
+  llvm::APSInt Tmin = ValueFactory

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-15 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1401-1402
+
+// FIXME: This case in particular is resulting in failed assertion.
+Range First = Range(Tmin, Max);
+Range Second = Range(Min, Tmax);

I changed the logic from using getCrucialPoints (which I mentioned in the 
e-mail thread) to simple checks to determine overflows using signedness. But 
the failed assertions again popped up. And I was unable to pin-point the issue 
here. Can someone help me?

Although, I am thinking of revising the above logic by using bitwise methods to 
detect overflows.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-16 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1397
+(LHS.To() < 0 && RHS.To() < 0 && Max > 0) ||
+(LHS.To() < 0 && RHS.To() < 0 && Max > 0)) {
+  return {RangeFactory, Tmin, Tmax};

vsavchenko wrote:
> This clause is exactly the same as the previous one, it is a mistake.
> And I think we should have a test that could've shown that.
> Also, since you are checking for overflows for both the beginning and the 
> end, we should have tests where both overflow.
Understood! I will add tests to check each OR part of these conditionals in 
these cases.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1401-1402
+
+// FIXME: This case in particular is resulting in failed assertion.
+Range First = Range(Tmin, Max);
+Range Second = Range(Min, Tmax);

vsavchenko wrote:
> vsavchenko wrote:
> > manas wrote:
> > > I changed the logic from using getCrucialPoints (which I mentioned in the 
> > > e-mail thread) to simple checks to determine overflows using signedness. 
> > > But the failed assertions again popped up. And I was unable to pin-point 
> > > the issue here. Can someone help me?
> > > 
> > > Although, I am thinking of revising the above logic by using bitwise 
> > > methods to detect overflows.
> > This is actually one place that I won't expect an assertion failure.
> > Can we get a bit more detail on it?  Is it again `From > To` (which will 
> > indeed be weird) or something different?
> > 
> > NOTE: Asking for help (either here or on StackOverflow) is a lot like 
> > filing a bug report, try to put as much information as possible, try to 
> > structure this information so it is easy to follow.  It's also good to tell 
> > people what you tried, instead of saying that you tried something and it 
> > didn't work.
> OK, I downloaded your patch and ran the debugger.
> 
> It complains about different bit-width for ranges that the analyzer tries to 
> intersect.  What I checked next: what are those ranges, so I took `begin()` 
> from one of them and checked what are `From` and `To` there.
> Here is one of them:
> ```
> (const llvm::APSInt) $8 = {
>   llvm::APInt = {
> U = {
>   VAL = 22
>   pVal = 0x0016
> }
> BitWidth = 4022311424
>   }
>   IsUnsigned = true
> }
> ```
> Woah, this `BitWidth` seems ridiculous!  What does it tell us?  It definitely 
> didn't get there as part of any reasonable logic, right?  So, what can it be 
> instead?  Only one answer here - garbage.  We have some sort of memory issue 
> with integers that we use as part of our ranges!  So, let's see what type of 
> information `Range` class actually stores:
> ```
> class Range {
> public:
>   Range(const llvm::APSInt &From, const llvm::APSInt &To) : Impl(&From, &To) {
> assert(From <= To);
>   }
> 
> ...
> 
> private:
>   std::pair Impl;
> };
> ```
> 
> What we have here is a pair of pointers, and you have:
> ```
>   llvm::APSInt Min = LHS.From() + RHS.From();
>   llvm::APSInt Max = LHS.To() + RHS.To();
>   llvm::APSInt Tmin = ValueFactory.getMinValue(ResultType);
>   llvm::APSInt Tmax = ValueFactory.getMaxValue(ResultType);
> ```
> These are ALL stack variables. So, pointer to those point to adequate data 
> ONLY while we are inside of our functions.  When we call another function, 
> these pointers point into some data from some other function in the call 
> stack, it doesn't point to anything even remotely resembling `llvm::APSInt` 
> and we get `BitWidth = 4022311424`.
> 
> OK, we figured out the problem, what about a solution?  If you look at other 
> implementations, you can notice a couple of interesting things.
> When you do:
> ```
> llvm::APSInt Tmin = ValueFactory.getMinValue(ResultType);
> ```
> other code does something like:
> ```
> const llvm::APSInt &Tmin = ValueFactory.getMinValue(ResultType);
> ```
> Or when you do:
> ```
> Range Second = Range(Min, Tmax);
> ```
> The sibling code does:
> ```
> return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)};
> ```
> 
> It looks like `ValueFactory` is the key here!  It actually manages the 
> lifetime of those integers for you and, whenever you ask it about values, it 
> gives you `llvm::APSInt &` (note the reference part) that will have the 
> correct lifetime.
> 
> I hope this gives you some insight into how you can debug things like this on 
> your own and how you can reason about what you see.
> 
> Another piece of advice is to look around, other `VisitBinaryOperator` 
> methods have all the information you actually needed.  If you don't 
> understand why we need `ValueFactory`, - experiment, ask us!  It's bad to 
> just ignore it.
Got it! I am working on fixing this. 



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1405-1406
+RangeSet ResultRangeSet = RangeFactory.getRangeSet(First);
+RangeSet ResultRangeSet2 =

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-16 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1409-1415
+  if ((LHS.From() > 0 && RHS.From() > 0 && Min < 0) ||
+  (LHS.From() < 0 && RHS.From() < 0 && Min > 0) ||
+  (LHS.To() > 0 && RHS.To() > 0 && Max < 0) ||
+  (LHS.To() < 0 && RHS.To() < 0 && Max > 0)) {
+// return [Tmin, Tmax]
+return {RangeFactory, Tmin, Tmax};
+  }

vsavchenko wrote:
> manas wrote:
> > vsavchenko wrote:
> > > I thought we talked quite a lot that there is nothing bad with overflows 
> > > and here we have that if ANY overflow happened, we bail out and don't 
> > > give any result.
> > Understood! Should I replace it with code returning EmptySet()?
> Why `EmptySet()`?  `EmptySet()` means that this can never happen, this path 
> is infeasible.  Is that the case?
> Let's say we have: `[INT_MAX - 20, INT_MAX - 10] + [30, 40]` what happens in 
> this case?
Right! That will not be the case.

In this particular case, the range will be `[INT_MIN + 9, INT_MIN + 29]` which 
is far smaller than `[Tmin, Tmax]`.

Also, I think I misunderstood the part of //bailing out and not giving any 
result// as returning empty.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-16 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1409-1415
+  if ((LHS.From() > 0 && RHS.From() > 0 && Min < 0) ||
+  (LHS.From() < 0 && RHS.From() < 0 && Min > 0) ||
+  (LHS.To() > 0 && RHS.To() > 0 && Max < 0) ||
+  (LHS.To() < 0 && RHS.To() < 0 && Max > 0)) {
+// return [Tmin, Tmax]
+return {RangeFactory, Tmin, Tmax};
+  }

vsavchenko wrote:
> manas wrote:
> > vsavchenko wrote:
> > > manas wrote:
> > > > vsavchenko wrote:
> > > > > I thought we talked quite a lot that there is nothing bad with 
> > > > > overflows and here we have that if ANY overflow happened, we bail out 
> > > > > and don't give any result.
> > > > Understood! Should I replace it with code returning EmptySet()?
> > > Why `EmptySet()`?  `EmptySet()` means that this can never happen, this 
> > > path is infeasible.  Is that the case?
> > > Let's say we have: `[INT_MAX - 20, INT_MAX - 10] + [30, 40]` what happens 
> > > in this case?
> > Right! That will not be the case.
> > 
> > In this particular case, the range will be `[INT_MIN + 9, INT_MIN + 29]` 
> > which is far smaller than `[Tmin, Tmax]`.
> > 
> > Also, I think I misunderstood the part of //bailing out and not giving any 
> > result// as returning empty.
> Gotcha!
> 
> Because of cases like this, you need to re-think that part about `Min > Max` 
> and maybe count the number of overflows on each side?
That's right. If it is able to deduce how many times overflows are occurring 
then it can reason about whether it will be MaxRangeSet or a subset of it. 
Fixing it!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-18 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 353168.
manas added a comment.

Reason about cases where Min > Max


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,83 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) < 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) > 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) < -1); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -964,6 +964,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Rem:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Add:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -1380,6 +1382,79 @@
   return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)};
 }
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
+Range RHS,
+QualType T) {
+  APSIntType ResultType = ValueFactory.getAPSIntType(T);
+  llvm::APSInt Min = LHS.From() + RHS.From();
+  llvm::APSInt Max = LHS.To() + RHS.To();
+  const llvm::APSInt &Tmin = ValueFactory.getMinValue(ResultType);
+  const llvm::APSInt &Tmax = ValueFactory.getMaxValue(ResultType);
+
+  if (Min 

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-18 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

The diff fixes all invalid assertion issues and also reasons about the cases 
where Min > Max.

One thing which is stuck for me is the case where Min <= Max but it overflows. 
I could reason about that in this way:

1. If one of Min/Max overflows while the other doesn't then the resulting range 
should be [Tmin, Tmax] as Min <= Max even after overflowing.
2. If both of them overflows, then: a. If both overflows on the same side, that 
is, both wrapped around Tmax, or both wrapped around Tmin, then the range 
should be [Min, Max] only. b. But if both overflowed in different sides, 
supposedly Min overflowed on left and Max on right, or vice versa, then the 
range will be [Tmin, Tmax].

Will it work?




Comment at: clang/test/Analysis/constant-folding.c:280-281
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}

When I pull these cases out to a separate function (say testAdditionRules2) in 
constant-folding.c then algorithm is able to reason about the range correctly, 
but inside testAdditionRules, it is unable to figure stuff out. Does it have 
something to do with constraints being propagated which we discussed below?

@vsavchenko wrote: 
> I have one note here.  The fact that we don't have a testing framework and 
> use this approach of inspecting the actual analysis has an interesting 
> implication.
> 
> ```
> if (a == 10) { // here we split path into 2 paths: one where a == 10, and one 
> where a != 10;
>// one goes inside of if, one doesn't
>   . . .
> }
> if (a >= 5) { // here we split into 3 paths: a == 10, a < 5, and a in [5, 9] 
> and [11, INT_MAX] (aka a >= 5 and a != 10).
>   // 1 path was infeasible: a == 10 and a < 5
>   // Two of these paths go inside of the if, one doesn't
>   . . .
>   clang_analyzer_eval(a == 10); // it will produce two results: TRUE and FALSE
> }
> clang_analyzer_eval(a == 10); // it will produce three results: TRUE, FALSE, 
> and FALSE
> ```
> 
> We don't want to test how path splitting works in these particular tests 
> (they are about solver and constant folding after all), that's why we try to 
> have only one path going through each `clang_analyzer_eval(...)`
> 




Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-21 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/test/Analysis/constant-folding.c:280-281
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}

vsavchenko wrote:
> manas wrote:
> > When I pull these cases out to a separate function (say testAdditionRules2) 
> > in constant-folding.c then algorithm is able to reason about the range 
> > correctly, but inside testAdditionRules, it is unable to figure stuff out. 
> > Does it have something to do with constraints being propagated which we 
> > discussed below?
> > 
> > @vsavchenko wrote: 
> > > I have one note here.  The fact that we don't have a testing framework 
> > > and use this approach of inspecting the actual analysis has an 
> > > interesting implication.
> > > 
> > > ```
> > > if (a == 10) { // here we split path into 2 paths: one where a == 10, and 
> > > one where a != 10;
> > >// one goes inside of if, one doesn't
> > >   . . .
> > > }
> > > if (a >= 5) { // here we split into 3 paths: a == 10, a < 5, and a in [5, 
> > > 9] and [11, INT_MAX] (aka a >= 5 and a != 10).
> > >   // 1 path was infeasible: a == 10 and a < 5
> > >   // Two of these paths go inside of the if, one doesn't
> > >   . . .
> > >   clang_analyzer_eval(a == 10); // it will produce two results: TRUE and 
> > > FALSE
> > > }
> > > clang_analyzer_eval(a == 10); // it will produce three results: TRUE, 
> > > FALSE, and FALSE
> > > ```
> > > 
> > > We don't want to test how path splitting works in these particular tests 
> > > (they are about solver and constant folding after all), that's why we try 
> > > to have only one path going through each `clang_analyzer_eval(...)`
> > > 
> > 
> > 
> It might be that or it might be something different.  Just by looking at this 
> example, the previous `if` statement shouldn't add more paths that go inside 
> of this `if`, so it shouldn't be the root cause.
> Whenever you encounter problems and you want to tell other people, **please, 
> provide more detail**.  Did you notice it when running the test case?  What 
> was the output?  What did you try?  How did you extract it into a separate 
> function?
I put a new test function in `constant-folding.c` as:

```
void testAdditionRulesNew(int c, int d) {
  if (c < 0 && c != INT_MIN && d < 0) {
clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
  }
}
```
I tested this specific function as:

  ./build/bin/clang -cc1 -analyze -analyzer-checker=core,debug.ExprInspection 
-analyze-function=testAdditionRulesNew constant-folding.c

And I got the following output:

  ../clang/test/Analysis/constant-folding.c:338:5: warning: FALSE 
[debug.ExprInspection]
clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}

which is correct.

But when I ran the same test inside `testAdditionRules`, using:
./build/bin/clang -cc1 -analyze -analyzer-checker=core,debug.ExprInspection 
-analyze-function=testAdditionRules constant-folding.c
then I got:

  ../clang/test/Analysis/constant-folding.c:281:5: warning: FALSE 
[debug.ExprInspection]
clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}} 
   
^  
  ../clang/test/Analysis/constant-folding.c:281:5: warning: TRUE 
[debug.ExprInspection]
clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}} 
   
^  

Here, `c = [INT_MIN + 1, -1]` and `d = [INT_MIN, 0]`, so `c + d = [INT_MIN, -2] 
U [1, INT_MAX]`. So `c + d == 0` should be false. But in latter case, it is 
reasoning `c + d == 0` to be `UNKNOWN`.

Also, the error arises in `c + d == 0` case only and not in `c + d == -1` case. 
I mistakenly highlighted that case while commenting.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-21 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1411
+if ((LHS.From() < 0 && RHS.From() < 0)) {
+  llvm::APSInt CrucialPoint = Tmin - LHS.From();
+  if (RHS.Includes(CrucialPoint)) {

vsavchenko wrote:
> What if `LHS.From()` is `Tmin` for signed `T`?
> What if `T` is unsigned?  Does `Tmin - LHS.From()` (aka `0 - LHS.From()`) 
> make sense?
Even if `LHS.From()` is `Tmin` for signed `T` the reasoning would be correct. 
As, CrucialPoint will be `Zero` and hence RHS will be divided into two parts: 
BeforeZero (`[RHS.From, Zero]`) and AfterAndIncludingZero (`[Zero, RHS.To]`).

And if the BeforeZero subrange (which will be responsible for overflowing, 
contains `Tmin + Tmax` then we can ensure that the final range will be `[Tmin, 
Tmax]`. And if it does not, (and assuming there is no overflow on the right 
side), then `1432:1434` will reason the range to be `[Tmin, Max] U [Min, Tmax]`.

For unsigned types, actually we are asking the wrong question because an 
addition of unsigned integers can never overflow from the left side. So in that 
case, the code deducing the overflows from left-side will not be applicable. 
And therefore, `0 - LHS.From()` will never give us anything. I was thinking to 
checked T before applying these rules.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1448-1451
+  if ((LHS.From() > 0 && RHS.From() > 0 && Min < 0) ||
+  (LHS.From() < 0 && RHS.From() < 0 && Min > 0) ||
+  (LHS.To() > 0 && RHS.To() > 0 && Max < 0) ||
+  (LHS.To() < 0 && RHS.To() < 0 && Max > 0)) {

vsavchenko wrote:
> Speaking of unsigned `T`, does it work for unsigned overflows?  Do we have 
> tests for that?
This was not going to make into the patch as it does not solve the case 
mentioned in FIXME(:1437).

An idea which I had in the previous post was this:

> 1. If one of Min/Max overflows while the other doesn't then the resulting 
> range should be [Tmin, Tmax] as Min <= Max even after overflowing.
> 2. If both of them overflows, then: a. If both overflows on the same side, 
> that is, both wrapped around Tmax, or both wrapped around Tmin, then the 
> range should be [Min, Max] only. b. But if both overflowed in different 
> sides, supposedly Min overflowed on left and Max on right, or vice versa, 
> then the range will be [Tmin, Tmax].



Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-21 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1395
+
+  if (Min > Max) {
+// This implies that an overflow has occured as either boundary would have

vsavchenko wrote:
> I commented on this part previously, you shouldn't get fixated on `Min > Max` 
> because `Max >= Min` doesn't imply that overflow didn't happen (less 
> important) and that the range `[Min, Max]` is correct (more important).  
> Recall one of the examples that I had in that email.
> 
> There is an interesting pattern about results that we can use:
> * no overflows happened -> `[Min, Max]` (should be always true)
> * 1 overflow happened -> we need to invert the range, but there are two 
> different cases:
> * `Min > Max`, perfect, that's what we expected -> `[Tmin, Max] ∪ [Min, 
> Tmax]`
> * `Max >= Min`, we overflowed and wrapped the whole range -> `[Tmin, 
> Tmax]`
> * 2 overflows happened on one side -> `[Min, Max]`
> * 2 overflows happened on both sides -> `[Tmin, Tmax]`
> 
> You need to think of this problem in terms of what really happens and not in 
> terms of combating with assertions.
I think I agree with you. This pattern (and the code following this pattern) 
makes much more sense, and easier to follow. I think I will refactor the patch 
accordingly. 


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-21 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/test/Analysis/constant-folding.c:280-281
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}

vsavchenko wrote:
> manas wrote:
> > vsavchenko wrote:
> > > manas wrote:
> > > > When I pull these cases out to a separate function (say 
> > > > testAdditionRules2) in constant-folding.c then algorithm is able to 
> > > > reason about the range correctly, but inside testAdditionRules, it is 
> > > > unable to figure stuff out. Does it have something to do with 
> > > > constraints being propagated which we discussed below?
> > > > 
> > > > @vsavchenko wrote: 
> > > > > I have one note here.  The fact that we don't have a testing 
> > > > > framework and use this approach of inspecting the actual analysis has 
> > > > > an interesting implication.
> > > > > 
> > > > > ```
> > > > > if (a == 10) { // here we split path into 2 paths: one where a == 10, 
> > > > > and one where a != 10;
> > > > >// one goes inside of if, one doesn't
> > > > >   . . .
> > > > > }
> > > > > if (a >= 5) { // here we split into 3 paths: a == 10, a < 5, and a in 
> > > > > [5, 9] and [11, INT_MAX] (aka a >= 5 and a != 10).
> > > > >   // 1 path was infeasible: a == 10 and a < 5
> > > > >   // Two of these paths go inside of the if, one doesn't
> > > > >   . . .
> > > > >   clang_analyzer_eval(a == 10); // it will produce two results: TRUE 
> > > > > and FALSE
> > > > > }
> > > > > clang_analyzer_eval(a == 10); // it will produce three results: TRUE, 
> > > > > FALSE, and FALSE
> > > > > ```
> > > > > 
> > > > > We don't want to test how path splitting works in these particular 
> > > > > tests (they are about solver and constant folding after all), that's 
> > > > > why we try to have only one path going through each 
> > > > > `clang_analyzer_eval(...)`
> > > > > 
> > > > 
> > > > 
> > > It might be that or it might be something different.  Just by looking at 
> > > this example, the previous `if` statement shouldn't add more paths that 
> > > go inside of this `if`, so it shouldn't be the root cause.
> > > Whenever you encounter problems and you want to tell other people, 
> > > **please, provide more detail**.  Did you notice it when running the test 
> > > case?  What was the output?  What did you try?  How did you extract it 
> > > into a separate function?
> > I put a new test function in `constant-folding.c` as:
> > 
> > ```
> > void testAdditionRulesNew(int c, int d) {
> >   if (c < 0 && c != INT_MIN && d < 0) {
> > clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
> >   }
> > }
> > ```
> > I tested this specific function as:
> > 
> >   ./build/bin/clang -cc1 -analyze 
> > -analyzer-checker=core,debug.ExprInspection 
> > -analyze-function=testAdditionRulesNew constant-folding.c
> > 
> > And I got the following output:
> > 
> >   ../clang/test/Analysis/constant-folding.c:338:5: warning: FALSE 
> > [debug.ExprInspection]
> > clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
> > 
> > which is correct.
> > 
> > But when I ran the same test inside `testAdditionRules`, using:
> > ./build/bin/clang -cc1 -analyze 
> > -analyzer-checker=core,debug.ExprInspection 
> > -analyze-function=testAdditionRules constant-folding.c
> > then I got:
> > 
> >   ../clang/test/Analysis/constant-folding.c:281:5: warning: FALSE 
> > [debug.ExprInspection]
> > clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}} 
> > 
> >
> > ^   
> >
> >   ../clang/test/Analysis/constant-folding.c:281:5: warning: TRUE 
> > [debug.ExprInspection]
> > clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}} 
> > 
> >
> > ^  
> > 
> > Here, `c = [INT_MIN + 1, -1]` and `d = [INT_MIN, 0]`, so `c + d = [INT_MIN, 
> > -2] U [1, INT_MAX]`. So `c + d == 0` should be false. But in latter case, 
> > it is reasoning `c + d == 0` to be `UNKNOWN`.
> > 
> > Also, the error arises in `c + d == 0` case only and not in `c + d == -1` 
> > case. I mistakenly highlighted that case while commenting.
> Hmm, I don't know what can be the reason.
> 
> There are three reasonable approaches:
> 1. Straightforward: use debugger.  Find a place when we ask the solver about 
> this assumption and dig in.
> 2. Print-based: use `clang_analyzer_printState` inside of this if.  Among 
> other things it will print you all constraints that we know about, you can 
> check if they match your expectations.  Also, if it is in

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-21 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/test/Analysis/constant-folding.c:280-281
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}

manas wrote:
> vsavchenko wrote:
> > manas wrote:
> > > vsavchenko wrote:
> > > > manas wrote:
> > > > > When I pull these cases out to a separate function (say 
> > > > > testAdditionRules2) in constant-folding.c then algorithm is able to 
> > > > > reason about the range correctly, but inside testAdditionRules, it is 
> > > > > unable to figure stuff out. Does it have something to do with 
> > > > > constraints being propagated which we discussed below?
> > > > > 
> > > > > @vsavchenko wrote: 
> > > > > > I have one note here.  The fact that we don't have a testing 
> > > > > > framework and use this approach of inspecting the actual analysis 
> > > > > > has an interesting implication.
> > > > > > 
> > > > > > ```
> > > > > > if (a == 10) { // here we split path into 2 paths: one where a == 
> > > > > > 10, and one where a != 10;
> > > > > >// one goes inside of if, one doesn't
> > > > > >   . . .
> > > > > > }
> > > > > > if (a >= 5) { // here we split into 3 paths: a == 10, a < 5, and a 
> > > > > > in [5, 9] and [11, INT_MAX] (aka a >= 5 and a != 10).
> > > > > >   // 1 path was infeasible: a == 10 and a < 5
> > > > > >   // Two of these paths go inside of the if, one doesn't
> > > > > >   . . .
> > > > > >   clang_analyzer_eval(a == 10); // it will produce two results: 
> > > > > > TRUE and FALSE
> > > > > > }
> > > > > > clang_analyzer_eval(a == 10); // it will produce three results: 
> > > > > > TRUE, FALSE, and FALSE
> > > > > > ```
> > > > > > 
> > > > > > We don't want to test how path splitting works in these particular 
> > > > > > tests (they are about solver and constant folding after all), 
> > > > > > that's why we try to have only one path going through each 
> > > > > > `clang_analyzer_eval(...)`
> > > > > > 
> > > > > 
> > > > > 
> > > > It might be that or it might be something different.  Just by looking 
> > > > at this example, the previous `if` statement shouldn't add more paths 
> > > > that go inside of this `if`, so it shouldn't be the root cause.
> > > > Whenever you encounter problems and you want to tell other people, 
> > > > **please, provide more detail**.  Did you notice it when running the 
> > > > test case?  What was the output?  What did you try?  How did you 
> > > > extract it into a separate function?
> > > I put a new test function in `constant-folding.c` as:
> > > 
> > > ```
> > > void testAdditionRulesNew(int c, int d) {
> > >   if (c < 0 && c != INT_MIN && d < 0) {
> > > clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
> > >   }
> > > }
> > > ```
> > > I tested this specific function as:
> > > 
> > >   ./build/bin/clang -cc1 -analyze 
> > > -analyzer-checker=core,debug.ExprInspection 
> > > -analyze-function=testAdditionRulesNew constant-folding.c
> > > 
> > > And I got the following output:
> > > 
> > >   ../clang/test/Analysis/constant-folding.c:338:5: warning: FALSE 
> > > [debug.ExprInspection]
> > > clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
> > > 
> > > which is correct.
> > > 
> > > But when I ran the same test inside `testAdditionRules`, using:
> > > ./build/bin/clang -cc1 -analyze 
> > > -analyzer-checker=core,debug.ExprInspection 
> > > -analyze-function=testAdditionRules constant-folding.c
> > > then I got:
> > > 
> > >   ../clang/test/Analysis/constant-folding.c:281:5: warning: FALSE 
> > > [debug.ExprInspection]
> > > clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}   
> > >   
> > >
> > > ^ 
> > >  
> > >   ../clang/test/Analysis/constant-folding.c:281:5: warning: TRUE 
> > > [debug.ExprInspection]
> > > clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}   
> > >   
> > >
> > > ^  
> > > 
> > > Here, `c = [INT_MIN + 1, -1]` and `d = [INT_MIN, 0]`, so `c + d = 
> > > [INT_MIN, -2] U [1, INT_MAX]`. So `c + d == 0` should be false. But in 
> > > latter case, it is reasoning `c + d == 0` to be `UNKNOWN`.
> > > 
> > > Also, the error arises in `c + d == 0` case only and not in `c + d == -1` 
> > > case. I mistakenly highlighted that case while commenting.
> > Hmm, I don't know what can be the reason.
> > 
> > There are three reasonable approaches:
> > 1. Straightforward: use debugger.  Find a place when we ask the solver 
> > about this assumption and dig in.

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-22 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 353825.
manas added a comment.

Added updated logic for reasoning using number of overflows. Also, changed a 
couple of tests which were leading to unwanted constriants being propagated 
further.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,81 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -964,6 +964,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Rem:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Add:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -1067,6 +1069,22 @@
 return {ValueFactory.getValue(-AbsMax), ValueFactory.getValue(AbsMax)};
   }
 
+  /// Check if an APSInt has overflowed by addition given LHSOpd and RHSOpd
+  /// TODO: Creating a generic abstraction for finding overflows when
+  ///   LHSOpd binop RHSOpd == Result, where binop is any binary operation
+  bool hasOverflowed(llvm::APSInt LHSOpd, llvm::APSInt RHSOpd,
+ llvm::APSInt &Result, QualType T) {
+llvm::APSInt Zero = ValueFactory.getAPSIntType(T).getZeroValue();
+
+// If both operands are positive then maximum possible overflow can only be
+// (--Zero) but when both ar

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-22 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

Regarding the tweakings in `constant-folding.c`, I have refrained from using 
cases which were resulting in `UNKNOWN` assertions as they were the primary 
reason for constraints being propagated.




Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1075-1076
+  ///   LHSOpd binop RHSOpd == Result, where binop is any binary operation
+  bool hasOverflowed(llvm::APSInt LHSOpd, llvm::APSInt RHSOpd,
+ llvm::APSInt &Result, QualType T) {
+llvm::APSInt Zero = ValueFactory.getAPSIntType(T).getZeroValue();

We should have these specific functions for other BO as well. Because they will 
lead us to reason about when `Operand1 binop Operand2` can overflow or not. I 
was thinking in the direction of having a simpler class which works for this.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-23 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

Thanks @vsavchenko and everyone for helping! :)




Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1075-1076
+  ///   LHSOpd binop RHSOpd == Result, where binop is any binary operation
+  bool hasOverflowed(llvm::APSInt LHSOpd, llvm::APSInt RHSOpd,
+ llvm::APSInt &Result, QualType T) {
+llvm::APSInt Zero = ValueFactory.getAPSIntType(T).getZeroValue();

vsavchenko wrote:
> manas wrote:
> > We should have these specific functions for other BO as well. Because they 
> > will lead us to reason about when `Operand1 binop Operand2` can overflow or 
> > not. I was thinking in the direction of having a simpler class which works 
> > for this.
> I searched through a codebase a bit and here are the couple of functions 
> (from `APInt.h`) that can come in handy:
> ```
>   // Operations that return overflow indicators.
>   APInt sadd_ov(const APInt &RHS, bool &Overflow) const;
>   APInt uadd_ov(const APInt &RHS, bool &Overflow) const;
>   APInt ssub_ov(const APInt &RHS, bool &Overflow) const;
>   APInt usub_ov(const APInt &RHS, bool &Overflow) const;
>   APInt sdiv_ov(const APInt &RHS, bool &Overflow) const;
>   APInt smul_ov(const APInt &RHS, bool &Overflow) const;
>   APInt umul_ov(const APInt &RHS, bool &Overflow) const;
>   APInt sshl_ov(const APInt &Amt, bool &Overflow) const;
>   APInt ushl_ov(const APInt &Amt, bool &Overflow) const;
> ```
> `APSInt` is derived from `APInt`, so we can totally use these.
That's great! I will incorporate those in the code instead of custom functions.



Comment at: clang/test/Analysis/constant-folding.c:269
+  // Checks for inclusive ranges for unsigned integers
+  if (a >= 0 && a <= 10 && b >= 0 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}

vsavchenko wrote:
> They are already unsigned, we don't need `a >= 0` and `b >= 0`
Right! I will remove those constraints.



Comment at: clang/test/Analysis/constant-folding.c:330
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}

vsavchenko wrote:
> I don't see the cases where we overflow on both ends and the case where we 
> overflow on one end, but `Min > Max`.
My bad. I thought I added both overflows one. I will add them now.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-23 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 354154.
manas added a comment.

Fix issues involving cases for unsigned type and add tests


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,93 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a <= 10 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Check when Max overflows from positive-side
+  if (c >= 10 && d >= 0 && d <= 10) {
+clang_analyzer_eval((c + d) == INT_MIN + 10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when Min overflows from negative side
+  if (c <= 10 && d >= -10 && d <= 0) {
+clang_analyzer_eval((c + d) == 11); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 10); // expected-warning{{FALSE}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -964,6 +964,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Rem:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Add:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -1380,6 +1382,63 @@
   return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)};
 }
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
+Range RHS,
+   

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-23 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1400
+  if (ResultType.isUnsigned()) {
+LHS.From().uadd_ov(RHS.From(), HasMinOverflowed);
+LHS.To().uadd_ov(RHS.To(), HasMaxOverflowed);

Using `uadd_ov` (and `sadd_ov`), we can get the added value as well as whether 
overflow occurred or not. A point is that these functions return `APInt` 
instead of `APSInt`.

But when I tried just using:
  Min = LHS.From().uadd_ov(RHS.From(), HasMinOverflowed);
  Max = LHS.To().uadd_ov(RHS.From(), HasMaxOverflowed);

instead of
  Min = LHS.From() + RHS.From();
  Max = LHS.To() + RHS.To();

just for the added value, then the following tests failed (//these tests and 
all other tests pass when I use the latter method to get Min/Max//):

  Clang :: Analysis/PR3991.m
  Clang :: Analysis/global-region-invalidation.c
  Clang :: Analysis/malloc-overflow2.c
  Clang :: Analysis/out-of-bounds-new.cpp
  Clang :: Analysis/taint-generic.c

I am working on fixing this part.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-24 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 354167.
manas added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,93 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a <= 10 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Check when Max overflows from positive-side
+  if (c >= 10 && d >= 0 && d <= 10) {
+clang_analyzer_eval((c + d) == INT_MIN + 10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when Min overflows from negative side
+  if (c <= 10 && d >= -10 && d <= 0) {
+clang_analyzer_eval((c + d) == 11); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 10); // expected-warning{{FALSE}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -964,6 +964,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Rem:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Add:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -1380,6 +1382,63 @@
   return {RangeFactory, ValueFactory.getValue(Min), ValueFactory.getValue(Max)};
 }
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
+Range RHS,
+QualTyp

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-24 Thread Manas Gupta via Phabricator via cfe-commits
manas marked an inline comment as not done.
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1400
+  if (ResultType.isUnsigned()) {
+LHS.From().uadd_ov(RHS.From(), HasMinOverflowed);
+LHS.To().uadd_ov(RHS.To(), HasMaxOverflowed);

vsavchenko wrote:
> manas wrote:
> > Using `uadd_ov` (and `sadd_ov`), we can get the added value as well as 
> > whether overflow occurred or not. A point is that these functions return 
> > `APInt` instead of `APSInt`.
> > 
> > But when I tried just using:
> >   Min = LHS.From().uadd_ov(RHS.From(), HasMinOverflowed);
> >   Max = LHS.To().uadd_ov(RHS.From(), HasMaxOverflowed);
> > 
> > instead of
> >   Min = LHS.From() + RHS.From();
> >   Max = LHS.To() + RHS.To();
> > 
> > just for the added value, then the following tests failed (//these tests 
> > and all other tests pass when I use the latter method to get Min/Max//):
> > 
> >   Clang :: Analysis/PR3991.m
> >   Clang :: Analysis/global-region-invalidation.c
> >   Clang :: Analysis/malloc-overflow2.c
> >   Clang :: Analysis/out-of-bounds-new.cpp
> >   Clang :: Analysis/taint-generic.c
> > 
> > I am working on fixing this part.
> You can easily construct `APSInt` from `APInt` using `APSInt ::APSInt(APInt 
> I, bool isUnsigned)` constructor.
Okay. I will try with using `uadd_ov` only then. And check whether those tests 
pass or not.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-24 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1400
+  if (ResultType.isUnsigned()) {
+LHS.From().uadd_ov(RHS.From(), HasMinOverflowed);
+LHS.To().uadd_ov(RHS.To(), HasMaxOverflowed);

vsavchenko wrote:
> manas wrote:
> > vsavchenko wrote:
> > > manas wrote:
> > > > Using `uadd_ov` (and `sadd_ov`), we can get the added value as well as 
> > > > whether overflow occurred or not. A point is that these functions 
> > > > return `APInt` instead of `APSInt`.
> > > > 
> > > > But when I tried just using:
> > > >   Min = LHS.From().uadd_ov(RHS.From(), HasMinOverflowed);
> > > >   Max = LHS.To().uadd_ov(RHS.From(), HasMaxOverflowed);
> > > > 
> > > > instead of
> > > >   Min = LHS.From() + RHS.From();
> > > >   Max = LHS.To() + RHS.To();
> > > > 
> > > > just for the added value, then the following tests failed (//these 
> > > > tests and all other tests pass when I use the latter method to get 
> > > > Min/Max//):
> > > >   Clang :: Analysis/PR3991.m
> > > >   Clang :: Analysis/global-region-invalidation.c
> > > >   Clang :: Analysis/malloc-overflow2.c
> > > >   Clang :: Analysis/out-of-bounds-new.cpp
> > > >   Clang :: Analysis/taint-generic.c
> > > > 
> > > > I am working on fixing this part.
> > > You can easily construct `APSInt` from `APInt` using `APSInt 
> > > ::APSInt(APInt I, bool isUnsigned)` constructor.
> > Okay. I will try with using `uadd_ov` only then. And check whether those 
> > tests pass or not.
> Hmm, why only `uadd_ov`?  What about those tests?  How do they fail?  Try to 
> look at the reasons and not brute-force by trying different solutions blindly.
> Those tests are your friends, it's much better to get failures right now then 
> getting them later when you land the patch.
I meant related functions as well.

Most of them were failing due to `Error evaluating statements`.  Although, I 
have rebased my tree so I will re-check again.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-24 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1400
+  if (ResultType.isUnsigned()) {
+LHS.From().uadd_ov(RHS.From(), HasMinOverflowed);
+LHS.To().uadd_ov(RHS.To(), HasMaxOverflowed);

vsavchenko wrote:
> manas wrote:
> > vsavchenko wrote:
> > > manas wrote:
> > > > vsavchenko wrote:
> > > > > manas wrote:
> > > > > > Using `uadd_ov` (and `sadd_ov`), we can get the added value as well 
> > > > > > as whether overflow occurred or not. A point is that these 
> > > > > > functions return `APInt` instead of `APSInt`.
> > > > > > 
> > > > > > But when I tried just using:
> > > > > >   Min = LHS.From().uadd_ov(RHS.From(), HasMinOverflowed);
> > > > > >   Max = LHS.To().uadd_ov(RHS.From(), HasMaxOverflowed);
> > > > > > 
> > > > > > instead of
> > > > > >   Min = LHS.From() + RHS.From();
> > > > > >   Max = LHS.To() + RHS.To();
> > > > > > 
> > > > > > just for the added value, then the following tests failed (//these 
> > > > > > tests and all other tests pass when I use the latter method to get 
> > > > > > Min/Max//): 
> > > > > >
> > > > > >   Clang :: Analysis/PR3991.m
> > > > > >   Clang :: Analysis/global-region-invalidation.c
> > > > > >   Clang :: Analysis/malloc-overflow2.c
> > > > > >   Clang :: Analysis/out-of-bounds-new.cpp
> > > > > >   Clang :: Analysis/taint-generic.c
> > > > > > 
> > > > > > I am working on fixing this part.
> > > > > You can easily construct `APSInt` from `APInt` using `APSInt 
> > > > > ::APSInt(APInt I, bool isUnsigned)` constructor.
> > > > Okay. I will try with using `uadd_ov` only then. And check whether 
> > > > those tests pass or not.
> > > Hmm, why only `uadd_ov`?  What about those tests?  How do they fail?  Try 
> > > to look at the reasons and not brute-force by trying different solutions 
> > > blindly.
> > > Those tests are your friends, it's much better to get failures right now 
> > > then getting them later when you land the patch.
> > I meant related functions as well.
> > 
> > Most of them were failing due to `Error evaluating statements`.  Although, 
> > I have rebased my tree so I will re-check again.
> `Error evaluating statements` just tells you when we crashed (for the context 
> and fast insight).
> Below this message is usually the real reason (and the last time I checked, 
> it was assertion `From > To` failure).
My bad. I took a look and found, it was signed mismatch!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106416: [analyzer] Fix build dependency issues for SATest

2021-08-02 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 363572.
manas added a comment.

upgrade cmake-3.21.0 to cmake-3.21.1


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106416/new/

https://reviews.llvm.org/D106416

Files:
  clang/utils/analyzer/Dockerfile


Index: clang/utils/analyzer/Dockerfile
===
--- clang/utils/analyzer/Dockerfile
+++ clang/utils/analyzer/Dockerfile
@@ -17,8 +17,9 @@
 gettext=0.19.8.1* \
 python3=3.6.7-1~18.04 \
 python3-pip=9.0.1-2.3* \
-cmake=3.20.5* \
-ninja-build=1.8.2-1
+cmake=3.21.1* \
+ninja-build=1.8.2-1 \
+ccache=3.4*
 
 # box2d dependencies
 RUN apt-get install -y \


Index: clang/utils/analyzer/Dockerfile
===
--- clang/utils/analyzer/Dockerfile
+++ clang/utils/analyzer/Dockerfile
@@ -17,8 +17,9 @@
 gettext=0.19.8.1* \
 python3=3.6.7-1~18.04 \
 python3-pip=9.0.1-2.3* \
-cmake=3.20.5* \
-ninja-build=1.8.2-1
+cmake=3.21.1* \
+ninja-build=1.8.2-1 \
+ccache=3.4*
 
 # box2d dependencies
 RUN apt-get install -y \
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D106416: [analyzer] Fix build dependency issues for SATest

2021-08-02 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

Fixing another broken dependency packages error.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D106416/new/

https://reviews.llvm.org/D106416

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D107312: [analyzer] Fix deprecated plistlib functions

2021-08-02 Thread Manas Gupta via Phabricator via cfe-commits
manas created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: teemperor.
manas requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

It replaces the usage of readPlist,writePlist functions with load,dump
in plistlib package.

This fixes deprecation issues when analyzer reports are being generated
outside of docker.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D107312

Files:
  clang/utils/analyzer/SATestBuild.py


Index: clang/utils/analyzer/SATestBuild.py
===
--- clang/utils/analyzer/SATestBuild.py
+++ clang/utils/analyzer/SATestBuild.py
@@ -847,7 +847,8 @@
 continue
 
 plist = os.path.join(dir_path, filename)
-data = plistlib.readPlist(plist)
+with open(plist, "rb") as plist_file:
+data = plistlib.load(plist_file)
 path_prefix = directory
 
 if build_mode == 1:
@@ -866,7 +867,8 @@
 if 'clang_version' in data:
 data.pop('clang_version')
 
-plistlib.writePlist(data, plist)
+with open(plist, "wb") as plist_file:
+plistlib.dump(data, plist_file)
 
 
 def get_build_log_path(output_dir: str) -> str:


Index: clang/utils/analyzer/SATestBuild.py
===
--- clang/utils/analyzer/SATestBuild.py
+++ clang/utils/analyzer/SATestBuild.py
@@ -847,7 +847,8 @@
 continue
 
 plist = os.path.join(dir_path, filename)
-data = plistlib.readPlist(plist)
+with open(plist, "rb") as plist_file:
+data = plistlib.load(plist_file)
 path_prefix = directory
 
 if build_mode == 1:
@@ -866,7 +867,8 @@
 if 'clang_version' in data:
 data.pop('clang_version')
 
-plistlib.writePlist(data, plist)
+with open(plist, "wb") as plist_file:
+plistlib.dump(data, plist_file)
 
 
 def get_build_log_path(output_dir: str) -> str:
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-08-03 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 363734.
manas added a comment.

Fix test comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c
  clang/utils/analyzer/Dockerfile
  clang/utils/analyzer/SATestBuild.py
  clang/utils/analyzer/entrypoint.py

Index: clang/utils/analyzer/entrypoint.py
===
--- clang/utils/analyzer/entrypoint.py
+++ clang/utils/analyzer/entrypoint.py
@@ -9,10 +9,11 @@
 
 def main():
 settings, rest = parse_arguments()
+cmake_opts = ['-D' + cmd for cmd in settings.D]
 if settings.wait:
 wait()
 if settings.build_llvm or settings.build_llvm_only:
-build_llvm()
+build_llvm(cmake_opts)
 if settings.build_llvm_only:
 return
 sys.exit(test(rest))
@@ -30,14 +31,15 @@
 parser.add_argument('--wait', action='store_true')
 parser.add_argument('--build-llvm', action='store_true')
 parser.add_argument('--build-llvm-only', action='store_true')
+parser.add_argument('-D', action='append', default=[])
 return parser.parse_known_args()
 
 
-def build_llvm():
+def build_llvm(cmake_options):
 os.chdir('/build')
 try:
 if is_cmake_needed():
-cmake()
+cmake(cmake_options)
 ninja()
 except CalledProcessError:
 print("Build failed!")
@@ -55,8 +57,9 @@
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 
 
-def cmake():
-check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+def cmake(cmake_options):
+check_call(CMAKE_COMMAND + ' '.join(cmake_options) + ' /llvm-project/llvm',
+shell=True)
 
 
 def ninja():
Index: clang/utils/analyzer/SATestBuild.py
===
--- clang/utils/analyzer/SATestBuild.py
+++ clang/utils/analyzer/SATestBuild.py
@@ -847,7 +847,8 @@
 continue
 
 plist = os.path.join(dir_path, filename)
-data = plistlib.readPlist(plist)
+with open(plist, "rb") as plist_file:
+data = plistlib.load(plist_file)
 path_prefix = directory
 
 if build_mode == 1:
@@ -866,7 +867,8 @@
 if 'clang_version' in data:
 data.pop('clang_version')
 
-plistlib.writePlist(data, plist)
+with open(plist, "wb") as plist_file:
+plistlib.dump(data, plist_file)
 
 
 def get_build_log_path(output_dir: str) -> str:
Index: clang/utils/analyzer/Dockerfile
===
--- clang/utils/analyzer/Dockerfile
+++ clang/utils/analyzer/Dockerfile
@@ -17,8 +17,9 @@
 gettext=0.19.8.1* \
 python3=3.6.7-1~18.04 \
 python3-pip=9.0.1-2.3* \
-cmake=3.20.5* \
-ninja-build=1.8.2-1
+cmake=3.21.1* \
+ninja-build=1.8.2-1 \
+ccache=3.4*
 
 # box2d dependencies
 RUN apt-get install -y \
Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,226 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Overflows on Tmax side
+  if (a >= 5 && a <= UINT_MAX - 5 && b <= 10) {
+clang_analyzer_eval((a + b) >= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a + b) <= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+  }
+
+  // Overflows on both ends
+  if (c >= INT_MIN + 5 && c <= INT_MAX - 5 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a <= 10 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+cl

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-08-03 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/utils/analyzer/Dockerfile:15-22
 RUN apt-get update && apt-get install -y \
 git=1:2.17.1* \
 gettext=0.19.8.1* \
 python3=3.6.7-1~18.04 \
 python3-pip=9.0.1-2.3* \
-cmake=3.20.5* \
-ninja-build=1.8.2-1
+cmake=3.21.1* \
+ninja-build=1.8.2-1 \

vsavchenko wrote:
> Changes to `clang/utils/analyzer/*` don't belong to this patch
I messed up while `arc updating`. :(


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-08-03 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 363742.
manas added a comment.

Fix unrelated commits mess up!


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,105 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Overflows on Tmax side
+  if (a >= 5 && a <= UINT_MAX - 5 && b <= 10) {
+clang_analyzer_eval((a + b) >= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a + b) <= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+  }
+
+  // Overflows on both ends
+  if (c >= INT_MIN + 5 && c <= INT_MAX - 5 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a <= 10 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Check when Max overflows from positive-side
+  if (c >= 10 && d >= 0 && d <= 10) {
+clang_analyzer_eval((c + d) == INT_MIN + 10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when Min overflows from negative side
+  if (c <= 10 && d >= -10 && d <= 0) {
+clang_analyzer_eval((c + d) == 11); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 10); // expected-warning{{FALSE}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -17,6 +17,7 @@
 #include "clang/StaticAnalyze

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-08-03 Thread Manas Gupta via Phabricator via cfe-commits
manas marked an inline comment as done.
manas added a comment.

I have updated the proof for Add: 
https://gist.github.com/weirdsmiley/ad6a9dbf3370e96d29f9e90068931d25


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105273: [analyzer] Introduce range-based reasoning for subtraction operator

2021-08-03 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D105273#2891921 , @manas wrote:

> Here is the proof using Z3: 
> https://gist.github.com/weirdsmiley/8a35a0e1f55f310e3566cbd47555491a

I have updated the proof for Sub.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105273/new/

https://reviews.llvm.org/D105273

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-24 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 354424.
manas added a comment.

Fix issues involving usage of `uadd_ov` and family of functions


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,93 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a <= 10 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Check when Max overflows from positive-side
+  if (c >= 10 && d >= 0 && d <= 10) {
+clang_analyzer_eval((c + d) == INT_MIN + 10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when Min overflows from negative side
+  if (c <= 10 && d >= -10 && d <= 0) {
+clang_analyzer_eval((c + d) == 11); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 10); // expected-warning{{FALSE}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -17,6 +17,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/SValVisitor.h"
+#include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
@@ -964,6 +965,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Rem:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_A

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-24 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 354441.
manas added a comment.

Add tests for overflows on both ends


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,104 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Overflows on both ends
+  if (a >= 5 && a <= UINT_MAX - 5 && b <= 10) {
+clang_analyzer_eval((a + b) >= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a + b) <= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= INT_MIN + 5 && c <= INT_MAX - 5 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a <= 10 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Check when Max overflows from positive-side
+  if (c >= 10 && d >= 0 && d <= 10) {
+clang_analyzer_eval((c + d) == INT_MIN + 10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when Min overflows from negative side
+  if (c <= 10 && d >= -10 && d <= 0) {
+clang_analyzer_eval((c + d) == 11); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 10); // expected-warning{{FALSE}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -17,6 +17,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/Pr

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-06-25 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/test/Analysis/constant-folding.c:330
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}

vsavchenko wrote:
> manas wrote:
> > vsavchenko wrote:
> > > I don't see the cases where we overflow on both ends and the case where 
> > > we overflow on one end, but `Min > Max`.
> > My bad. I thought I added both overflows one. I will add them now.
> This comment is marked as "Done", but I still don't these cases.
Amended. From line 260 and later.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-07-01 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 355825.
manas added a comment.

Reformat comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,104 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Overflows on both ends
+  if (a >= 5 && a <= UINT_MAX - 5 && b <= 10) {
+clang_analyzer_eval((a + b) >= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a + b) <= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= INT_MIN + 5 && c <= INT_MAX - 5 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a <= 10 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Check when Max overflows from positive-side
+  if (c >= 10 && d >= 0 && d <= 10) {
+clang_analyzer_eval((c + d) == INT_MIN + 10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when Min overflows from negative side
+  if (c <= 10 && d >= -10 && d <= 0) {
+clang_analyzer_eval((c + d) == 11); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 10); // expected-warning{{FALSE}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -17,6 +17,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"

[PATCH] D105273: [analyzer] Introduce range-based reasoning for subtraction operator

2021-07-01 Thread Manas Gupta via Phabricator via cfe-commits
manas created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: teemperor.
manas requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Add logic for computing rangesets for symbolic subtraction operator and
add test cases.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105273

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -352,3 +352,78 @@
 clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
   }
 }
+
+void testSubtractionRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when Max overflows but encompasses entire rangeset
+  if (c <= 0 && d <= 0) {
+// (c - d) = [INT_MIN, INT_MAX]
+clang_analyzer_eval((c - d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when both limits overflow from the opposite ends
+  if (c >= INT_MIN + 40 && c <= INT_MAX - 40 && d >= -50 && d <= 50) {
+// (c - d) = [INT_MIN, INT_MAX]
+clang_analyzer_eval((c - d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for non-overflowing ranges
+  if (a >= 10 && a <= 40 && b >= 5 && b <= 10) {
+// (a - b) = [0, 35]
+clang_analyzer_eval((a - b) <= 35); // expected-warning{{TRUE}}
+  }
+
+  if (c >= -10 && c <= 10 && d >= -20 && d <= 20) {
+// (c - d) = [-30, 30]
+clang_analyzer_eval((c - d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c - d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Check when Min overflows from lower bounded side
+  if (a <= 10 && b <= 10) {
+// (a - b) = [0, 10] U [UINT_MAX - 9, UINT_MAX]
+clang_analyzer_eval((a - b) != 11); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) != UINT_MAX - 10); // expected-warning{{TRUE}}
+  }
+
+  if (c <= 10 && d >= -30 && d <= 30) {
+// (c - d) = [INT_MIN, 40] U [INT_MAX - 29, INT_MAX]
+clang_analyzer_eval((c - d) != INT_MAX - 30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c - d) != 41); // expected-warning{{TRUE}}
+  }
+
+  // Checks when Max overflows from the upper bound side
+  if (a >= UINT_MAX - 10 && b >= UINT_MAX - 5) {
+// (a - b) = [0, 5] U [UINT_MAX - 9, UINT_MAX]
+clang_analyzer_eval((a - b) != 6); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) != UINT_MAX - 10); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) <= 5); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a - b) >= UINT_MAX - 9); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= INT_MAX - 5 && d >= INT_MAX - 5) {
+// (c - d) = [-5, 5]
+clang_analyzer_eval((c - d) < -5 ); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) > 5 ); // expected-warning{{FALSE}}
+  }
+
+  // Checks for Min and Max overflowing from same end
+  if (a <= 50 && b >= 60 && b <= 100) {
+// (a - b) = [UINT_MAX - 99, UINT_MAX - 9]
+clang_analyzer_eval((a - b) > UINT_MAX - 9); // expected-warning{{FALSE}}
+clang_analyzer_eval((a - b) < UINT_MAX - 99); // expected-warning{{FALSE}}
+  }
+
+  if (c <= INT_MIN + 50 && d >= INT_MIN + 60 && d <= INT_MIN + 100) {
+// (c - d) = [-100, -10]
+clang_analyzer_eval((c - d) > -10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) < -100); // expected-warning{{FALSE}}
+  }
+
+  if (c >= INT_MAX - 50 && d >= INT_MIN + 70 && d <= INT_MIN + 90) {
+// (c - d) = [-141, -71]
+clang_analyzer_eval((c - d) < -141); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -967,6 +967,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Add:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Sub:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -1438,6 +1440,74 @@
   return {RangeFactory, Tmin, Tmax};
 }
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
+Range RHS,
+QualType T) {
+  APSIntType ResultType = ValueFactory.getAPSIntType(T);
+  const llvm::APSInt &Tmin = ValueFactory.getMinValue(ResultType);
+  const llvm::APSInt &Tmax = Va

[PATCH] D105273: [analyzer] Introduce range-based reasoning for subtraction operator

2021-07-02 Thread Manas Gupta via Phabricator via cfe-commits
manas marked 3 inline comments as done.
manas added a comment.

Thanks Valeriy.




Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1490
+  // the resulting range should be [Min, Max].
+  if (ResultType.isUnsigned()) {
+return {RangeFactory, ValueFactory.getValue(Min),

vsavchenko wrote:
> Maybe you can include this as yet another condition in the next `if` 
> statement?  Their bodies are identical.
True. I wanted to optimize the following `if` condition as it looks quite ugly 
right now! Although, I will concatenate these conditions for now and work on 
the optimization later.



Comment at: clang/test/Analysis/constant-folding.c:399
+// (a - b) = [0, 5] U [UINT_MAX - 9, UINT_MAX]
+clang_analyzer_eval((a - b) != 6); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) != UINT_MAX - 10); // expected-warning{{TRUE}}

vsavchenko wrote:
> Maybe you can check `(a - b) > 5 && (a - b) < UINT_MAX - 9` to cover the 
> whole range?
That's true! I never thought of putting them together. Makes more sense.



Comment at: clang/test/Analysis/constant-folding.c:405
+
+  if (c >= INT_MAX - 5 && d >= INT_MAX - 5) {
+// (c - d) = [-5, 5]

vsavchenko wrote:
> This is also Min and Max overflowing on the positive side.
I missed it! I will add another case for only Max overflowing on positive side 
and will keep this test as well.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105273/new/

https://reviews.llvm.org/D105273

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105273: [analyzer] Introduce range-based reasoning for subtraction operator

2021-07-02 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 356235.
manas marked 3 inline comments as done.
manas added a comment.

Merge conditionals with similar block and add test for one overflow on Tmax-side


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105273/new/

https://reviews.llvm.org/D105273

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -352,3 +352,86 @@
 clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
   }
 }
+
+void testSubtractionRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when Max overflows but encompasses entire rangeset
+  if (c <= 0 && d <= 0) {
+// (c - d) = [INT_MIN, INT_MAX]
+clang_analyzer_eval((c - d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when both limits overflow from the opposite ends
+  if (c >= INT_MIN + 40 && c <= INT_MAX - 40 && d >= -50 && d <= 50) {
+// (c - d) = [INT_MIN, INT_MAX]
+clang_analyzer_eval((c - d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for non-overflowing ranges
+  if (a >= 10 && a <= 40 && b >= 5 && b <= 10) {
+// (a - b) = [0, 35]
+clang_analyzer_eval((a - b) <= 35); // expected-warning{{TRUE}}
+  }
+
+  if (c >= -10 && c <= 10 && d >= -20 && d <= 20) {
+// (c - d) = [-30, 30]
+clang_analyzer_eval((c - d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c - d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Check when Min overflows from lower bounded side
+  if (a <= 10 && b <= 10) {
+// (a - b) = [0, 10] U [UINT_MAX - 9, UINT_MAX]
+clang_analyzer_eval((a - b) != 11); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) != UINT_MAX - 10); // expected-warning{{TRUE}}
+  }
+
+  if (c <= 10 && d >= -30 && d <= 30) {
+// (c - d) = [INT_MIN, 40] U [INT_MAX - 29, INT_MAX]
+clang_analyzer_eval((c - d) != INT_MAX - 30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c - d) != 41); // expected-warning{{TRUE}}
+  }
+
+  // Checks when Max overflows from the upper bound side
+  if (a >= UINT_MAX - 10 && b >= UINT_MAX - 5) {
+// (a - b) = [0, 5] U [UINT_MAX - 9, UINT_MAX]
+clang_analyzer_eval((a - b) != 6); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) != UINT_MAX - 10); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) <= 5); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a - b) >= UINT_MAX - 9); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a - b) > 5 && (a - b) < UINT_MAX - 9); // expected-warning{{FALSE}}
+  }
+
+  if (c >= INT_MAX - 50 && d >= -50 && d <= 50) {
+// (c - d) = [INT_MIN, INT_MIN + 49] U [INT_MAX - 100, INT_MAX]
+clang_analyzer_eval((c - d) >= INT_MAX - 100); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) <= INT_MIN + 49); // expected-warning{{UNKNOWN}}
+  }
+
+  // Check when both overflow from the same side
+  if (c >= INT_MAX - 5 && d >= INT_MAX - 5) {
+// (c - d) = [-5, 5]
+clang_analyzer_eval((c - d) < -5 ); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) > 5 ); // expected-warning{{FALSE}}
+  }
+
+  // Checks for Min and Max overflowing from same end
+  if (a <= 50 && b >= 60 && b <= 100) {
+// (a - b) = [UINT_MAX - 99, UINT_MAX - 9]
+clang_analyzer_eval((a - b) > UINT_MAX - 9); // expected-warning{{FALSE}}
+clang_analyzer_eval((a - b) < UINT_MAX - 99); // expected-warning{{FALSE}}
+  }
+
+  if (c <= INT_MIN + 50 && d >= INT_MIN + 60 && d <= INT_MIN + 100) {
+// (c - d) = [-100, -10]
+clang_analyzer_eval((c - d) > -10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) < -100); // expected-warning{{FALSE}}
+  }
+
+  if (c >= INT_MAX - 50 && d >= INT_MIN + 70 && d <= INT_MIN + 90) {
+// (c - d) = [-141, -71]
+clang_analyzer_eval((c - d) < -141); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -958,6 +958,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Add:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Sub:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -1429,6 +1431,71 @@
   return {RangeFactory, Tmin, Tmax};
 }
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
+ 

[PATCH] D105273: [analyzer] Introduce range-based reasoning for subtraction operator

2021-07-02 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1485
+  if (ResultType.isUnsigned() ||
+  ((LHS.From() >= 0 && RHS.From() < 0) &&
+   (LHS.To() >= 0 && RHS.To() < 0)) ||

@vsavchenko one thing crossed my mind is that, shouldn't I compare `From` and 
`To` values with  `llvm::APSInt Zero = 
ValueFactory.getAPSIntType(T).getZeroValue()` instead of literal `0`?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105273/new/

https://reviews.llvm.org/D105273

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105273: [analyzer] Introduce range-based reasoning for subtraction operator

2021-07-02 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 356245.
manas added a comment.

Replace literal-value 0 with APSInt Zero


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105273/new/

https://reviews.llvm.org/D105273

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -352,3 +352,86 @@
 clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
   }
 }
+
+void testSubtractionRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when Max overflows but encompasses entire rangeset
+  if (c <= 0 && d <= 0) {
+// (c - d) = [INT_MIN, INT_MAX]
+clang_analyzer_eval((c - d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when both limits overflow from the opposite ends
+  if (c >= INT_MIN + 40 && c <= INT_MAX - 40 && d >= -50 && d <= 50) {
+// (c - d) = [INT_MIN, INT_MAX]
+clang_analyzer_eval((c - d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for non-overflowing ranges
+  if (a >= 10 && a <= 40 && b >= 5 && b <= 10) {
+// (a - b) = [0, 35]
+clang_analyzer_eval((a - b) <= 35); // expected-warning{{TRUE}}
+  }
+
+  if (c >= -10 && c <= 10 && d >= -20 && d <= 20) {
+// (c - d) = [-30, 30]
+clang_analyzer_eval((c - d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c - d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Check when Min overflows from lower bounded side
+  if (a <= 10 && b <= 10) {
+// (a - b) = [0, 10] U [UINT_MAX - 9, UINT_MAX]
+clang_analyzer_eval((a - b) != 11); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) != UINT_MAX - 10); // expected-warning{{TRUE}}
+  }
+
+  if (c <= 10 && d >= -30 && d <= 30) {
+// (c - d) = [INT_MIN, 40] U [INT_MAX - 29, INT_MAX]
+clang_analyzer_eval((c - d) != INT_MAX - 30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c - d) != 41); // expected-warning{{TRUE}}
+  }
+
+  // Checks when Max overflows from the upper bound side
+  if (a >= UINT_MAX - 10 && b >= UINT_MAX - 5) {
+// (a - b) = [0, 5] U [UINT_MAX - 9, UINT_MAX]
+clang_analyzer_eval((a - b) != 6); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) != UINT_MAX - 10); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) <= 5); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a - b) >= UINT_MAX - 9); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a - b) > 5 && (a - b) < UINT_MAX - 9); // expected-warning{{FALSE}}
+  }
+
+  if (c >= INT_MAX - 50 && d >= -50 && d <= 50) {
+// (c - d) = [INT_MIN, INT_MIN + 49] U [INT_MAX - 100, INT_MAX]
+clang_analyzer_eval((c - d) >= INT_MAX - 100); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) <= INT_MIN + 49); // expected-warning{{UNKNOWN}}
+  }
+
+  // Check when both overflow from the same side
+  if (c >= INT_MAX - 5 && d >= INT_MAX - 5) {
+// (c - d) = [-5, 5]
+clang_analyzer_eval((c - d) < -5 ); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) > 5 ); // expected-warning{{FALSE}}
+  }
+
+  // Checks for Min and Max overflowing from same end
+  if (a <= 50 && b >= 60 && b <= 100) {
+// (a - b) = [UINT_MAX - 99, UINT_MAX - 9]
+clang_analyzer_eval((a - b) > UINT_MAX - 9); // expected-warning{{FALSE}}
+clang_analyzer_eval((a - b) < UINT_MAX - 99); // expected-warning{{FALSE}}
+  }
+
+  if (c <= INT_MIN + 50 && d >= INT_MIN + 60 && d <= INT_MIN + 100) {
+// (c - d) = [-100, -10]
+clang_analyzer_eval((c - d) > -10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) < -100); // expected-warning{{FALSE}}
+  }
+
+  if (c >= INT_MAX - 50 && d >= INT_MIN + 70 && d <= INT_MIN + 90) {
+// (c - d) = [-141, -71]
+clang_analyzer_eval((c - d) < -141); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -958,6 +958,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Add:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Sub:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -1429,6 +1431,72 @@
   return {RangeFactory, Tmin, Tmax};
 }
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
+Range RHS,
+ 

[PATCH] D105273: [analyzer] Introduce range-based reasoning for subtraction operator

2021-07-02 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 356249.
manas added a comment.

Remove redundant getAPSIntType calls


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105273/new/

https://reviews.llvm.org/D105273

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -352,3 +352,86 @@
 clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
   }
 }
+
+void testSubtractionRules(unsigned int a, unsigned int b, int c, int d) {
+  // Checks when Max overflows but encompasses entire rangeset
+  if (c <= 0 && d <= 0) {
+// (c - d) = [INT_MIN, INT_MAX]
+clang_analyzer_eval((c - d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when both limits overflow from the opposite ends
+  if (c >= INT_MIN + 40 && c <= INT_MAX - 40 && d >= -50 && d <= 50) {
+// (c - d) = [INT_MIN, INT_MAX]
+clang_analyzer_eval((c - d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for non-overflowing ranges
+  if (a >= 10 && a <= 40 && b >= 5 && b <= 10) {
+// (a - b) = [0, 35]
+clang_analyzer_eval((a - b) <= 35); // expected-warning{{TRUE}}
+  }
+
+  if (c >= -10 && c <= 10 && d >= -20 && d <= 20) {
+// (c - d) = [-30, 30]
+clang_analyzer_eval((c - d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c - d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Check when Min overflows from lower bounded side
+  if (a <= 10 && b <= 10) {
+// (a - b) = [0, 10] U [UINT_MAX - 9, UINT_MAX]
+clang_analyzer_eval((a - b) != 11); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) != UINT_MAX - 10); // expected-warning{{TRUE}}
+  }
+
+  if (c <= 10 && d >= -30 && d <= 30) {
+// (c - d) = [INT_MIN, 40] U [INT_MAX - 29, INT_MAX]
+clang_analyzer_eval((c - d) != INT_MAX - 30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c - d) != 41); // expected-warning{{TRUE}}
+  }
+
+  // Checks when Max overflows from the upper bound side
+  if (a >= UINT_MAX - 10 && b >= UINT_MAX - 5) {
+// (a - b) = [0, 5] U [UINT_MAX - 9, UINT_MAX]
+clang_analyzer_eval((a - b) != 6); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) != UINT_MAX - 10); // expected-warning{{TRUE}}
+clang_analyzer_eval((a - b) <= 5); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a - b) >= UINT_MAX - 9); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a - b) > 5 && (a - b) < UINT_MAX - 9); // expected-warning{{FALSE}}
+  }
+
+  if (c >= INT_MAX - 50 && d >= -50 && d <= 50) {
+// (c - d) = [INT_MIN, INT_MIN + 49] U [INT_MAX - 100, INT_MAX]
+clang_analyzer_eval((c - d) >= INT_MAX - 100); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c - d) <= INT_MIN + 49); // expected-warning{{UNKNOWN}}
+  }
+
+  // Check when both overflow from the same side
+  if (c >= INT_MAX - 5 && d >= INT_MAX - 5) {
+// (c - d) = [-5, 5]
+clang_analyzer_eval((c - d) < -5 ); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) > 5 ); // expected-warning{{FALSE}}
+  }
+
+  // Checks for Min and Max overflowing from same end
+  if (a <= 50 && b >= 60 && b <= 100) {
+// (a - b) = [UINT_MAX - 99, UINT_MAX - 9]
+clang_analyzer_eval((a - b) > UINT_MAX - 9); // expected-warning{{FALSE}}
+clang_analyzer_eval((a - b) < UINT_MAX - 99); // expected-warning{{FALSE}}
+  }
+
+  if (c <= INT_MIN + 50 && d >= INT_MIN + 60 && d <= INT_MIN + 100) {
+// (c - d) = [-100, -10]
+clang_analyzer_eval((c - d) > -10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) < -100); // expected-warning{{FALSE}}
+  }
+
+  if (c >= INT_MAX - 50 && d >= INT_MIN + 70 && d <= INT_MIN + 90) {
+// (c - d) = [-141, -71]
+clang_analyzer_eval((c - d) < -141); // expected-warning{{FALSE}}
+clang_analyzer_eval((c - d) > -71); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -958,6 +958,8 @@
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_Add:
   return VisitBinaryOperator(LHS, RHS, T);
+case BO_Sub:
+  return VisitBinaryOperator(LHS, RHS, T);
 default:
   return infer(T);
 }
@@ -1429,6 +1431,72 @@
   return {RangeFactory, Tmin, Tmax};
 }
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS,
+Range RHS,
+ 

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-07-02 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 356250.
manas added a comment.

Replace literal-value 0 with APSInt Zero


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,104 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Overflows on both ends
+  if (a >= 5 && a <= UINT_MAX - 5 && b <= 10) {
+clang_analyzer_eval((a + b) >= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a + b) <= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= INT_MIN + 5 && c <= INT_MAX - 5 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a <= 10 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Check when Max overflows from positive-side
+  if (c >= 10 && d >= 0 && d <= 10) {
+clang_analyzer_eval((c + d) == INT_MIN + 10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when Min overflows from negative side
+  if (c <= 10 && d >= -10 && d <= 0) {
+clang_analyzer_eval((c + d) == 11); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 10); // expected-warning{{FALSE}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -17,6 +17,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitiv

[PATCH] D103440: [WIP][analyzer] Introduce range-based reasoning for addition operator

2021-07-02 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 356256.
manas added a comment.

Rebase


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D103440/new/

https://reviews.llvm.org/D103440

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -251,3 +251,104 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testAdditionRules(unsigned int a, unsigned int b, int c, int d) {
+  if (a == 0) {
+clang_analyzer_eval((a + 0) == 0); // expected-warning{{TRUE}}
+  }
+
+  // Overflows on both ends
+  if (a >= 5 && a <= UINT_MAX - 5 && b <= 10) {
+clang_analyzer_eval((a + b) >= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((a + b) <= UINT_MAX >> 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c >= INT_MIN + 5 && c <= INT_MAX - 5 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) <= 0); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for unsigned operands
+  clang_analyzer_eval((a + b) < 0); // expected-warning{{FALSE}}
+  clang_analyzer_eval((a + b) <= UINT_MAX); // expected-warning{{TRUE}}
+
+  if (a == UINT_MAX && b == UINT_MAX) {
+clang_analyzer_eval((a + b) == UINT_MAX - 1); // expected-warning{{TRUE}}
+  }
+
+  // Checks for inclusive ranges for unsigned integers
+  if (a <= 10 && b <= 20) {
+clang_analyzer_eval((a + b) >= 0); // expected-warning{{TRUE}}
+clang_analyzer_eval((a + b) > 30); // expected-warning{{FALSE}}
+  }
+
+  // Checks for negative signed integers
+  if (c < 0 && d < 0) {
+clang_analyzer_eval((c + d) != -1); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c != INT_MIN && d < 0) {
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) <= -2); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= 1); // expected-warning{{UNKNOWN}}
+  }
+
+  if (c == INT_MIN && d == INT_MIN) {
+clang_analyzer_eval((c + d) == 0); // expected-warning{{TRUE}}
+  }
+
+  if (c == INT_MIN && d < 0 && d != INT_MIN) {
+clang_analyzer_eval((c + d) > 0); // expected-warning{{TRUE}}
+  }
+
+  if (c < 0 && c >= -20 && d < 0 && d >= -40) {
+clang_analyzer_eval((c + d) < -1); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) >= -60); // expected-warning{{TRUE}}
+  }
+
+  // Checks for integers with different sign bits
+  if (c < 0 && d > 0) {
+if (c >= -20 && d <= 10) {
+  clang_analyzer_eval((c + d) > -20); // expected-warning{{TRUE}}
+  clang_analyzer_eval((c + d) < 10); // expected-warning{{TRUE}}
+}
+  }
+
+  // Checks for overlapping signed integers ranges
+  if (c >= -20 && c <= 20 && d >= -10 && d <= 10) {
+clang_analyzer_eval((c + d) >= -30); // expected-warning{{TRUE}}
+clang_analyzer_eval((c + d) <= 30); // expected-warning{{TRUE}}
+  }
+
+  // Checks for positive signed integers
+  if (c > 0 && d > 0) {
+clang_analyzer_eval((c + d) == 1); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == 0); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Check when Max overflows from positive-side
+  if (c >= 10 && d >= 0 && d <= 10) {
+clang_analyzer_eval((c + d) == INT_MIN + 10); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == -1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when Min overflows from negative side
+  if (c <= 10 && d >= -10 && d <= 0) {
+clang_analyzer_eval((c + d) == 11); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 10); // expected-warning{{FALSE}}
+  }
+
+  // Checks producing overflowing range with different signs
+  int HALF_INT_MAX = INT_MAX / 2;
+  if (c >= HALF_INT_MAX - 10 && c <= HALF_INT_MAX + 10 &&
+  d >= HALF_INT_MAX - 10 && d <= HALF_INT_MAX + 10) {
+// The resulting range for (c + d) will be:
+//   [INT_MIN, INT_MIN + 18] U [INT_MAX - 21, INT_MAX]
+clang_analyzer_eval((c + d) <= INT_MIN + 18); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) >= INT_MAX - 21); // expected-warning{{UNKNOWN}}
+clang_analyzer_eval((c + d) == INT_MIN + 19); // expected-warning{{FALSE}}
+clang_analyzer_eval((c + d) == INT_MAX - 22); // expected-warning{{FALSE}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -17,6 +17,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
 #include "

[PATCH] D105447: [analyzer] Allow cmake options to be passed to satest container

2021-07-05 Thread Manas Gupta via Phabricator via cfe-commits
manas created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: teemperor.
manas requested review of this revision.
Herald added a reviewer: jdoerfert.
Herald added subscribers: cfe-commits, sstefan1.
Herald added a project: clang.

This patch selects all cmake options and passes them to global cmake
command while building LLVM inside satest docker container.

Prior to this, the cmake command was hard-coded and this would consume
a huge amount of memory while building. There was no support to pass
extra cmake options for the build, except for changing the command
manually. This patch allows testers to pass all "-D*" cmake options to
the build.

It also removes -DLLVM_BUILD_RUNTIME cmake option from the hard-coded
cmake command as it was allowing the build to hog up a lot of memory.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D105447

Files:
  clang/utils/analyzer/entrypoint.py


Index: clang/utils/analyzer/entrypoint.py
===
--- clang/utils/analyzer/entrypoint.py
+++ clang/utils/analyzer/entrypoint.py
@@ -9,10 +9,11 @@
 
 def main():
 settings, rest = parse_arguments()
+cmake_opts = list(filter(lambda cmd: cmd[:2]=='-D', rest))
 if settings.wait:
 wait()
 if settings.build_llvm or settings.build_llvm_only:
-build_llvm()
+build_llvm(cmake_opts)
 if settings.build_llvm_only:
 return
 sys.exit(test(rest))
@@ -33,11 +34,11 @@
 return parser.parse_known_args()
 
 
-def build_llvm():
+def build_llvm(cmake_options):
 os.chdir('/build')
 try:
 if is_cmake_needed():
-cmake()
+cmake(cmake_options)
 ninja()
 except CalledProcessError:
 print("Build failed!")
@@ -50,13 +51,14 @@
 
 CMAKE_COMMAND = "cmake -G Ninja -DCMAKE_BUILD_TYPE=Release " \
 "-DCMAKE_INSTALL_PREFIX=/analyzer -DLLVM_TARGETS_TO_BUILD=X86 " \
-"-DLLVM_ENABLE_PROJECTS=\"clang;openmp\" -DLLVM_BUILD_RUNTIME=OFF " \
+"-DLLVM_ENABLE_PROJECTS=\"clang;openmp\" " \
 "-DLLVM_ENABLE_TERMINFO=OFF -DCLANG_ENABLE_ARCMT=OFF " \
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 
 
-def cmake():
-check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+def cmake(cmake_options):
+check_call(CMAKE_COMMAND + ' '.join(cmake_options) + ' /llvm-project/llvm',
+shell=True)
 
 
 def ninja():


Index: clang/utils/analyzer/entrypoint.py
===
--- clang/utils/analyzer/entrypoint.py
+++ clang/utils/analyzer/entrypoint.py
@@ -9,10 +9,11 @@
 
 def main():
 settings, rest = parse_arguments()
+cmake_opts = list(filter(lambda cmd: cmd[:2]=='-D', rest))
 if settings.wait:
 wait()
 if settings.build_llvm or settings.build_llvm_only:
-build_llvm()
+build_llvm(cmake_opts)
 if settings.build_llvm_only:
 return
 sys.exit(test(rest))
@@ -33,11 +34,11 @@
 return parser.parse_known_args()
 
 
-def build_llvm():
+def build_llvm(cmake_options):
 os.chdir('/build')
 try:
 if is_cmake_needed():
-cmake()
+cmake(cmake_options)
 ninja()
 except CalledProcessError:
 print("Build failed!")
@@ -50,13 +51,14 @@
 
 CMAKE_COMMAND = "cmake -G Ninja -DCMAKE_BUILD_TYPE=Release " \
 "-DCMAKE_INSTALL_PREFIX=/analyzer -DLLVM_TARGETS_TO_BUILD=X86 " \
-"-DLLVM_ENABLE_PROJECTS=\"clang;openmp\" -DLLVM_BUILD_RUNTIME=OFF " \
+"-DLLVM_ENABLE_PROJECTS=\"clang;openmp\" " \
 "-DLLVM_ENABLE_TERMINFO=OFF -DCLANG_ENABLE_ARCMT=OFF " \
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 
 
-def cmake():
-check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+def cmake(cmake_options):
+check_call(CMAKE_COMMAND + ' '.join(cmake_options) + ' /llvm-project/llvm',
+shell=True)
 
 
 def ninja():
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105447: [analyzer] Allow cmake options to be passed to satest container

2021-07-05 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 356574.
manas added a comment.

Restore global cmake command


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105447/new/

https://reviews.llvm.org/D105447

Files:
  clang/utils/analyzer/entrypoint.py


Index: clang/utils/analyzer/entrypoint.py
===
--- clang/utils/analyzer/entrypoint.py
+++ clang/utils/analyzer/entrypoint.py
@@ -9,10 +9,11 @@
 
 def main():
 settings, rest = parse_arguments()
+cmake_opts = list(filter(lambda cmd: cmd[:2]=='-D', rest))
 if settings.wait:
 wait()
 if settings.build_llvm or settings.build_llvm_only:
-build_llvm()
+build_llvm(cmake_opts)
 if settings.build_llvm_only:
 return
 sys.exit(test(rest))
@@ -33,11 +34,11 @@
 return parser.parse_known_args()
 
 
-def build_llvm():
+def build_llvm(cmake_options):
 os.chdir('/build')
 try:
 if is_cmake_needed():
-cmake()
+cmake(cmake_options)
 ninja()
 except CalledProcessError:
 print("Build failed!")
@@ -55,8 +56,9 @@
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 
 
-def cmake():
-check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+def cmake(cmake_options):
+check_call(CMAKE_COMMAND + ' '.join(cmake_options) + ' /llvm-project/llvm',
+shell=True)
 
 
 def ninja():


Index: clang/utils/analyzer/entrypoint.py
===
--- clang/utils/analyzer/entrypoint.py
+++ clang/utils/analyzer/entrypoint.py
@@ -9,10 +9,11 @@
 
 def main():
 settings, rest = parse_arguments()
+cmake_opts = list(filter(lambda cmd: cmd[:2]=='-D', rest))
 if settings.wait:
 wait()
 if settings.build_llvm or settings.build_llvm_only:
-build_llvm()
+build_llvm(cmake_opts)
 if settings.build_llvm_only:
 return
 sys.exit(test(rest))
@@ -33,11 +34,11 @@
 return parser.parse_known_args()
 
 
-def build_llvm():
+def build_llvm(cmake_options):
 os.chdir('/build')
 try:
 if is_cmake_needed():
-cmake()
+cmake(cmake_options)
 ninja()
 except CalledProcessError:
 print("Build failed!")
@@ -55,8 +56,9 @@
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 
 
-def cmake():
-check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+def cmake(cmake_options):
+check_call(CMAKE_COMMAND + ' '.join(cmake_options) + ' /llvm-project/llvm',
+shell=True)
 
 
 def ninja():
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105447: [analyzer] Allow cmake options to be passed to satest container

2021-07-05 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D105447#2858740 , @manas wrote:

> Restore global cmake command

Apparently, my initial observation of `LLVM_BUILD_RUNTIME=OFF` hogging up 
memory was false and I also didn't know what was the default value for this 
option. Hence, I have restored the global cmake command to its previous state.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105447/new/

https://reviews.llvm.org/D105447

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105447: [analyzer] Allow cmake options to be passed to satest container

2021-07-05 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 356575.
manas edited the summary of this revision.
manas added a comment.

Edit summary


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105447/new/

https://reviews.llvm.org/D105447

Files:
  clang/utils/analyzer/entrypoint.py


Index: clang/utils/analyzer/entrypoint.py
===
--- clang/utils/analyzer/entrypoint.py
+++ clang/utils/analyzer/entrypoint.py
@@ -9,10 +9,11 @@
 
 def main():
 settings, rest = parse_arguments()
+cmake_opts = list(filter(lambda cmd: cmd[:2]=='-D', rest))
 if settings.wait:
 wait()
 if settings.build_llvm or settings.build_llvm_only:
-build_llvm()
+build_llvm(cmake_opts)
 if settings.build_llvm_only:
 return
 sys.exit(test(rest))
@@ -33,11 +34,11 @@
 return parser.parse_known_args()
 
 
-def build_llvm():
+def build_llvm(cmake_options):
 os.chdir('/build')
 try:
 if is_cmake_needed():
-cmake()
+cmake(cmake_options)
 ninja()
 except CalledProcessError:
 print("Build failed!")
@@ -55,8 +56,9 @@
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 
 
-def cmake():
-check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+def cmake(cmake_options):
+check_call(CMAKE_COMMAND + ' '.join(cmake_options) + ' /llvm-project/llvm',
+shell=True)
 
 
 def ninja():


Index: clang/utils/analyzer/entrypoint.py
===
--- clang/utils/analyzer/entrypoint.py
+++ clang/utils/analyzer/entrypoint.py
@@ -9,10 +9,11 @@
 
 def main():
 settings, rest = parse_arguments()
+cmake_opts = list(filter(lambda cmd: cmd[:2]=='-D', rest))
 if settings.wait:
 wait()
 if settings.build_llvm or settings.build_llvm_only:
-build_llvm()
+build_llvm(cmake_opts)
 if settings.build_llvm_only:
 return
 sys.exit(test(rest))
@@ -33,11 +34,11 @@
 return parser.parse_known_args()
 
 
-def build_llvm():
+def build_llvm(cmake_options):
 os.chdir('/build')
 try:
 if is_cmake_needed():
-cmake()
+cmake(cmake_options)
 ninja()
 except CalledProcessError:
 print("Build failed!")
@@ -55,8 +56,9 @@
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 
 
-def cmake():
-check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+def cmake(cmake_options):
+check_call(CMAKE_COMMAND + ' '.join(cmake_options) + ' /llvm-project/llvm',
+shell=True)
 
 
 def ninja():
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105447: [analyzer] Allow cmake options to be passed to satest container

2021-07-06 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/utils/analyzer/entrypoint.py:12
 settings, rest = parse_arguments()
+cmake_opts = list(filter(lambda cmd: cmd[:2]=='-D', rest))
 if settings.wait:

vsavchenko wrote:
> I think we should still use `argparse` for stuff like this, and we don't want 
> any of these flags to sneak into `rest`.
> https://stackoverflow.com/a/31141568/11582326
Understood! I will rework on this. Thanks for the review.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105447/new/

https://reviews.llvm.org/D105447

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D105447: [analyzer] Allow cmake options to be passed to satest container

2021-07-06 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 356821.
manas added a comment.

Pass commands through settings instead of rest


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D105447/new/

https://reviews.llvm.org/D105447

Files:
  clang/utils/analyzer/entrypoint.py


Index: clang/utils/analyzer/entrypoint.py
===
--- clang/utils/analyzer/entrypoint.py
+++ clang/utils/analyzer/entrypoint.py
@@ -9,10 +9,11 @@
 
 def main():
 settings, rest = parse_arguments()
+cmake_opts = ['-D' + cmd for cmd in settings.D]
 if settings.wait:
 wait()
 if settings.build_llvm or settings.build_llvm_only:
-build_llvm()
+build_llvm(cmake_opts)
 if settings.build_llvm_only:
 return
 sys.exit(test(rest))
@@ -30,14 +31,15 @@
 parser.add_argument('--wait', action='store_true')
 parser.add_argument('--build-llvm', action='store_true')
 parser.add_argument('--build-llvm-only', action='store_true')
+parser.add_argument('-D', action='append', default=[])
 return parser.parse_known_args()
 
 
-def build_llvm():
+def build_llvm(cmake_options):
 os.chdir('/build')
 try:
 if is_cmake_needed():
-cmake()
+cmake(cmake_options)
 ninja()
 except CalledProcessError:
 print("Build failed!")
@@ -55,8 +57,9 @@
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 
 
-def cmake():
-check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+def cmake(cmake_options):
+check_call(CMAKE_COMMAND + ' '.join(cmake_options) + ' /llvm-project/llvm',
+shell=True)
 
 
 def ninja():


Index: clang/utils/analyzer/entrypoint.py
===
--- clang/utils/analyzer/entrypoint.py
+++ clang/utils/analyzer/entrypoint.py
@@ -9,10 +9,11 @@
 
 def main():
 settings, rest = parse_arguments()
+cmake_opts = ['-D' + cmd for cmd in settings.D]
 if settings.wait:
 wait()
 if settings.build_llvm or settings.build_llvm_only:
-build_llvm()
+build_llvm(cmake_opts)
 if settings.build_llvm_only:
 return
 sys.exit(test(rest))
@@ -30,14 +31,15 @@
 parser.add_argument('--wait', action='store_true')
 parser.add_argument('--build-llvm', action='store_true')
 parser.add_argument('--build-llvm-only', action='store_true')
+parser.add_argument('-D', action='append', default=[])
 return parser.parse_known_args()
 
 
-def build_llvm():
+def build_llvm(cmake_options):
 os.chdir('/build')
 try:
 if is_cmake_needed():
-cmake()
+cmake(cmake_options)
 ninja()
 except CalledProcessError:
 print("Build failed!")
@@ -55,8 +57,9 @@
 "-DCLANG_ENABLE_STATIC_ANALYZER=ON"
 
 
-def cmake():
-check_call(CMAKE_COMMAND + ' /llvm-project/llvm', shell=True)
+def cmake(cmake_options):
+check_call(CMAKE_COMMAND + ' '.join(cmake_options) + ' /llvm-project/llvm',
+shell=True)
 
 
 def ninja():
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2021-10-27 Thread Manas Gupta via Phabricator via cfe-commits
manas created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
Herald added a reviewer: teemperor.
manas requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

With this patch, the solver can infer results for not equal to operator
over Ranges as well. This also fixes the issue of comparison between
different types, by first converting the RangeSets to resulting type,
which then can be used for comparisons.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D112621

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,49 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, int s1, int s2) {
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval((s1 != s2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval((u1 != u2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -20,8 +20,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -957,6 +957,8 @@
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
RangeSet RHS, QualType T) {
 switch (Op) {
+case BO_NE:
+  return VisitBinaryOperator(LHS, RHS, T);
 case BO_Or:
   return VisitBinaryOperator(LHS, RHS, T);
 case BO_And:
@@ -1231,6 +1233,26 @@
 //   Range-based reasoning about symbolic operations
 //===--===//
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS, Range RHS,
+   QualType T) {
+  // When both the Ranges are non-overlapping then all possible pairs of (x, y)
+  // in LHS, RHS respectively, will satisfy expression (x != y).
+  if ((LHS.To() < RHS.From()) || (LHS.From() > RHS.To())) {
+return getTrueRange(T);
+  }
+
+  // If both Ranges contain only one Point which is equal, then the expression
+  // will always return true.
+  if ((LHS.From() == RHS.To()) && (LHS.To() == RHS.To()) &&
+  (LHS.From() == RHS.From())) {
+return getFalseRange(T);
+  }
+
+  // In all other cases, the resulting range cannot be deduced.
+  return infer(T);
+}
+
 template <>
 RangeSet SymbolicRangeInferrer::VisitBinaryOperator(Range LHS, Range RHS,
QualType T) {
@@ -1721,7 +1743,6 @@
   RangeSet::Factory &RangeFactory;
 };
 
-
 bool ConstraintAssignor::assignSymExprToConst(const SymExpr *Sym,
   const llvm::APSInt &Constraint) {
   llvm::SmallSet SimplifiedCl

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2021-10-27 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

@steakhal @martong This patch solves the comparison between different types by 
bypassing the RangeSets first to `VisitBinaryOperator` which coarses/converts, 
and then only it checks for any True/False ranges via comparison. This is 
similar to what happens with `BO_Rem`, `BO_And` etc. as well.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2021-10-27 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

In D112621#3090450 , @steakhal wrote:

> It seems like the test does not exercise the modified code segment.
> Please investigate, and make sure that the code you submit is actually 
> exercised by the test you provide.

I am really sorry. I will fix it soon.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D114758: [analyzer][solver] Introduce reasoning for not equal to operator

2021-11-29 Thread Manas Gupta via Phabricator via cfe-commits
manas created this revision.
Herald added subscribers: steakhal, ASDenysPetrov, martong, dkrupp, donat.nagy, 
Szelethus, mikhail.ramalho, a.sidorin, szepet, baloghadamsoftware, xazax.hun.
manas requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

With this patch, the solver can infer results for not equal to operator
over Ranges as well. This also fixes the issue of comparison between
different types, by first converting the RangeSets to resulting type,
which then can be used for comparisons.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D114758

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,55 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, int s1, int s2) {
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval((s1 != s2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval((u1 != u2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for comparison between different types
+  if (u1 <= 255 && s1 <= 0) {
+// u1: [0, 255], s1: [INT_MIN, 0]
+clang_analyzer_eval((u1 != s1) == 0); // expected-warning{{UNKNOWN}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -20,8 +20,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -960,18 +960,7 @@
   }
 
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
-   RangeSet RHS, QualType T) {
-switch (Op) {
-case BO_Or:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_And:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_Rem:
-  return VisitBinaryOperator(LHS, RHS, T);
-default:
-  return infer(T);
-}
-  }
+   RangeSet RHS, QualType T);
 
   //===--===//
   // Ranges and operators
@@ -1236,6 +1225,67 @@
 //   Range-based reasoning about symbolic operations
 //===--===//
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,
+   RangeSet RHS,
+   QualType T) {
+
+  // We must check for empty RangeSets. This gets done via VisitBinaryOperator
+  // for other operators, but BO_NE is handled specifically.
+  if (LHS.isEmpty() || RHS.isEmpty()) {
+return RangeFactory.getEmptySet();
+  }
+
+  APSIntType ResultType = ValueFactory.getAPSIntType(T);
+
+  RangeSet ConvertedLHS = RangeFactory.getEmptySet();
+  RangeSet ConvertedRHS = RangeFactory.getEmptySet();
+
+  // Convert each Range inside the RangeSet t

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2021-11-29 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 390526.
manas added a comment.

Fix comparison between different types and add a test to check it


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,55 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, int s1, int s2) {
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval((s1 != s2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval((u1 != u2) != 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval((u1 != u2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 <= -500 && s2 >= -750) {
+// s1: [-1000,-500], s2: [-500,-750]
+clang_analyzer_eval((s1 != s2) == 0); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for comparison between different types
+  if (u1 <= 255 && s1 <= 0) {
+// u1: [0, 255], s1: [INT_MIN, 0]
+clang_analyzer_eval((u1 != s1) == 0); // expected-warning{{UNKNOWN}}
+  }
+}
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -20,8 +20,8 @@
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/ImmutableSet.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include 
@@ -960,18 +960,7 @@
   }
 
   RangeSet VisitBinaryOperator(RangeSet LHS, BinaryOperator::Opcode Op,
-   RangeSet RHS, QualType T) {
-switch (Op) {
-case BO_Or:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_And:
-  return VisitBinaryOperator(LHS, RHS, T);
-case BO_Rem:
-  return VisitBinaryOperator(LHS, RHS, T);
-default:
-  return infer(T);
-}
-  }
+   RangeSet RHS, QualType T);
 
   //===--===//
   // Ranges and operators
@@ -1236,6 +1225,67 @@
 //   Range-based reasoning about symbolic operations
 //===--===//
 
+template <>
+RangeSet SymbolicRangeInferrer::VisitBinaryOperator(RangeSet LHS,
+   RangeSet RHS,
+   QualType T) {
+
+  // We must check for empty RangeSets. This gets done via VisitBinaryOperator
+  // for other operators, but BO_NE is handled specifically.
+  if (LHS.isEmpty() || RHS.isEmpty()) {
+return RangeFactory.getEmptySet();
+  }
+
+  APSIntType ResultType = ValueFactory.getAPSIntType(T);
+
+  RangeSet ConvertedLHS = RangeFactory.getEmptySet();
+  RangeSet ConvertedRHS = RangeFactory.getEmptySet();
+
+  // Convert each Range inside the RangeSet to given type. This will make it
+  // possible to have comparisons between different APSInts.
+  for (auto LRange : LHS) {
+auto ConvertedLRange = convert(LRange, ResultType);
+
+// If any of the converted Range is not bounded within the limits of the
+// type, then we must not compare the APSInt values. Hence, we have no
+// option 

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2021-11-29 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

I have made few changes:

1. The failed assertions  due to comparison 
between different types have been fixed by converting all the Ranges to a given 
type. This will allow comparisons without throwing errors.

2. There was also a build error due to `explicit specialization in 
non-namespace scope`. This was fixed by @martong previously, but that patch led 
to the above mentioned bug. So I used @martong 's patch here to make GCC happy.

3. I have added a small check for comparison between different types.

https://reviews.llvm.org/D106102 differential contains the background story.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D114758: [analyzer][solver] Introduce reasoning for not equal to operator

2021-11-29 Thread Manas Gupta via Phabricator via cfe-commits
manas added a comment.

Closing this as this is mistakenly a duplicate of existing differential D112621 
.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D114758/new/

https://reviews.llvm.org/D114758

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-09-29 Thread Manas Gupta via Phabricator via cfe-commits
manas updated this revision to Diff 463910.
manas added a comment.

Fix casting to bigger/unsigned type and add tests with multiple ranges in 
RangeSet


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

Files:
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/test/Analysis/constant-folding.c

Index: clang/test/Analysis/constant-folding.c
===
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -281,3 +281,149 @@
 clang_analyzer_eval((b % a) < x + 10); // expected-warning{{TRUE}}
   }
 }
+
+void testDisequalityRules(unsigned int u1, unsigned int u2, unsigned int u3,
+  int s1, int s2, int s3, unsigned char uch,
+  signed char sch, short ssh, unsigned short ush) {
+  // Checks for overflowing values
+  if (u1 > INT_MAX && u1 <= UINT_MAX / 2 + 4 && u1 != UINT_MAX / 2 + 2 &&
+  u1 != UINT_MAX / 2 + 3 && s1 >= INT_MIN + 1 && s1 <= INT_MIN + 2) {
+// u1: [INT_MAX+1, INT_MAX+1]U[INT_MAX+4, INT_MAX+4],
+// s1: [INT_MIN+1, INT_MIN+2]
+clang_analyzer_eval(u1 != s1); // expected-warning{{TRUE}}
+  }
+
+  if (u1 > INT_MAX && u1 <= UINT_MAX / 2 + 4 && u1 != UINT_MAX / 2 + 2 &&
+  u1 != UINT_MAX / 2 + 3 && s1 >= INT_MIN + 1 && s1 <= INT_MIN + 2) {
+// u1: [INT_MAX+1, INT_MAX+1]U[INT_MAX+4, INT_MAX+4],
+// s1: [INT_MIN+1, INT_MIN+2]
+clang_analyzer_eval(u1 != s1); // expected-warning{{TRUE}}
+  }
+
+  if (u1 >= INT_MIN && u1 <= INT_MIN + 2 &&
+  s1 > INT_MIN + 2 && s1 < INT_MIN + 4) {
+// u1: [INT_MAX+1, INT_MAX+1]U[INT_MAX+4, INT_MAX+4],
+// s1: [INT_MIN+3, INT_MIN+3]
+clang_analyzer_eval(u1 != s1); // expected-warning{{TRUE}}
+  }
+
+  if (s1 < 0 && s1 > -4 && u1 > UINT_MAX - 4 && u1 < UINT_MAX - 1) {
+// s1: [-3, -1], u1: [UINT_MAX - 3, UINT_MAX - 2]
+clang_analyzer_eval(u1 != s1); // expected-warning{{TRUE}}
+  }
+
+  if (s1 < 1 && s1 > -6 && s1 != -4 && s1 != -3 &&
+  u1 > UINT_MAX - 4 && u1 < UINT_MAX - 1) {
+// s1: [-5, -5]U[-2, 0], u1: [UINT_MAX - 3, UINT_MAX - 2]
+clang_analyzer_eval(u1 != s1); // expected-warning{{TRUE}}
+  }
+
+  if (s1 < 1 && s1 > -7 && s1 != -4 && s1 != -3 &&
+  u1 > UINT_MAX - 4 && u1 < UINT_MAX - 1) {
+// s1: [-6, -5]U[-2, 0], u1: [UINT_MAX - 3, UINT_MAX - 2]
+clang_analyzer_eval(u1 != s1); // expected-warning{{TRUE}}
+  }
+
+  // Check when RHS is in between two Ranges in LHS
+  if (((u1 >= 1 && u1 <= 2) || (u1 >= 8 && u1 <= 9)) &&
+  u2 >= 5 && u2 <= 6) {
+// u1: [1, 2]U[8, 9], u2: [5, 6]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  // Checks for concrete value with same type
+  if (u1 > 1 && u1 < 3 && u2 > 1 && u2 < 3) {
+// u1: [2, 2], u2: [2, 2]
+clang_analyzer_eval(u1 != u2); // expected-warning{{FALSE}}
+  }
+
+  // Check for concrete value with different types
+  if (u1 > 4 && u1 < 6 && s1 > 4 && s1 < 6) {
+// u1: [5, 5], s1: [5, 5]
+clang_analyzer_eval(u1 != s1); // expected-warning{{FALSE}}
+  }
+
+  // Checks when ranges are not overlapping
+  if (u1 <= 10 && u2 >= 20) {
+// u1: [0,10], u2: [20,UINT_MAX]
+clang_analyzer_eval(u1 != u2); // expected-warning{{TRUE}}
+  }
+
+  if (s1 <= INT_MIN + 10 && s2 >= INT_MAX - 10) {
+// s1: [INT_MIN,INT_MIN + 10], s2: [INT_MAX - 10,INT_MAX]
+clang_analyzer_eval(s1 != s2); // expected-warning{{TRUE}}
+  }
+
+  // Checks when ranges are completely overlapping and have more than one point
+  if (u1 >= 20 && u1 <= 50 && u2 >= 20 && u2 <= 50) {
+// u1: [20,50], u2: [20,50]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -20 && s1 <= 20 && s2 >= -20 && s2 <= 20) {
+// s1: [-20,20], s2: [-20,20]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks when ranges are partially overlapping
+  if (u1 >= 100 && u1 <= 200 && u2 >= 150 && u2 <= 300) {
+// u1: [100,200], u2: [150,300]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -80 && s1 <= -50 && s2 >= -100 && s2 <= -75) {
+// s1: [-80,-50], s2: [-100,-75]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for ranges which are subset of one-another
+  if (u1 >= 500 && u1 <= 1000 && u2 >= 750 && u2 <= 1000) {
+// u1: [500,1000], u2: [750,1000]
+clang_analyzer_eval(u1 != u2); // expected-warning{{UNKNOWN}}
+  }
+
+  if (s1 >= -1000 && s1 <= -500 && s2 >= -750 && s2 <= -500) {
+// s1: [-1000,-500], s2: [-750, -500]
+clang_analyzer_eval(s1 != s2); // expected-warning{{UNKNOWN}}
+  }
+
+  // Checks for comparison between different types
+  // Using different variables as previous constraints may interfere in the
+  // reasoning.
+  if (u3 <= 255 && s3 < 0) {
+// u3: [0, 255], s3: [INT_MIN, -1]
+clang_analyzer_eval(u3 != s3

[PATCH] D112621: [analyzer][solver] Introduce reasoning for not equal to operator

2022-09-29 Thread Manas Gupta via Phabricator via cfe-commits
manas marked 3 inline comments as done.
manas added a comment.

Thanks @martong and @ASDenysPetrov for the feedback. I utilized `(u != n)` to 
disallow bifurcation in test cases.




Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1630-1631
+
+  RangeSet CastedLHS = RangeFactory.castTo(LHS, ResultType);
+  RangeSet CastedRHS = RangeFactory.castTo(RHS, ResultType);
+

ASDenysPetrov wrote:
> And again. This is incorrect to cast your `un/signeds` to `bool`.
> First, `castTo` currently does not support this operation correctly AFAIR (My 
> fault. I'll add the support later). And thus, I've no idea why your tests 
> pass.
> Second, you will get from e.g. `u32[1,9]`  -  `bool[1,1]` and from `i32[42, 
> 45]` - `bool[1,1]`. Then `bool[1,1]` would be equal to `bool[1,1]`, but it 
> shouldn't in terms of `u/i32`.
> 
> Here you should emulate the behavior of C++ abstract machine, hence cast both 
> to the biggest type or unsigned one.
So I figured out that according to [C standard]( 
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#%5B%7B%22num%22%3A194%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C-27%2C816%2Cnull%5D)
 an expression of `x != y` has `int` as resulting type, while [C++ 
standard](https://isocpp.org/files/papers/N4860.pdf#subsection.7.6.10) makes it 
a bool. And as test file `constant-folding.c` contains tests for C, I was 
unintentionally casting RangeSets to `int`, and that is why those tests were 
passing. Do you think we should add a C++ test file, similar to 
`constant-folding.c` in the suite?



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1630-1631
+
+  RangeSet CastedLHS = RangeFactory.castTo(LHS, ResultType);
+  RangeSet CastedRHS = RangeFactory.castTo(RHS, ResultType);
+

manas wrote:
> ASDenysPetrov wrote:
> > And again. This is incorrect to cast your `un/signeds` to `bool`.
> > First, `castTo` currently does not support this operation correctly AFAIR 
> > (My fault. I'll add the support later). And thus, I've no idea why your 
> > tests pass.
> > Second, you will get from e.g. `u32[1,9]`  -  `bool[1,1]` and from `i32[42, 
> > 45]` - `bool[1,1]`. Then `bool[1,1]` would be equal to `bool[1,1]`, but it 
> > shouldn't in terms of `u/i32`.
> > 
> > Here you should emulate the behavior of C++ abstract machine, hence cast 
> > both to the biggest type or unsigned one.
> So I figured out that according to [C standard]( 
> https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#%5B%7B%22num%22%3A194%2C%22gen%22%3A0%7D%2C%7B%22name%22%3A%22XYZ%22%7D%2C-27%2C816%2Cnull%5D)
>  an expression of `x != y` has `int` as resulting type, while [C++ 
> standard](https://isocpp.org/files/papers/N4860.pdf#subsection.7.6.10) makes 
> it a bool. And as test file `constant-folding.c` contains tests for C, I was 
> unintentionally casting RangeSets to `int`, and that is why those tests were 
> passing. Do you think we should add a C++ test file, similar to 
> `constant-folding.c` in the suite?
Apart from the tests, consider the example of LHS (8-bit, signed) and RHS 
(16-bit, unsigned).

`LHS = [-2, -1]` and `RHS = [128, 129]` which ideally should produce `LHS != 
RHS -> true` but after casting smaller signed type to bigger unsigned 
type(`CastedLHS = [128,129]`), we may have incorrect information. Should we not 
cast to bigger **signed** type instead of bigger **unsigned** type?

Also, I think for cases where smaller bitwidth is signed(say type `T1`), and 
bigger bitwidth is unsigned(say type `T2`), we should "bisect" smaller signed 
type rangeset into following rangesets:

`bisect(LHS) => [LHS.MinValue, LHS.MaxNegativeValueLessThanZero] U 
[LHS.MinPositiveValueGreaterThanEqualToZero, LHS.MaxValue]`

and we can show that, first RangeSet of above can never have an intersection 
with RHS(unsigned) type, so we only care about the second RangeSet in 
`bisect(LHS)`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D112621/new/

https://reviews.llvm.org/D112621

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D140086: [analyzer][solver] Improve reasoning for not equal to operator

2022-12-18 Thread Manas Gupta via Phabricator via cfe-commits
manas added inline comments.



Comment at: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp:1642
+if (LHS.isUnsigned() ^ RHS.isUnsigned()) {
+  if (LHS.isUnsigned() && (LHS.getBitWidth() >= RHS.getBitWidth())) {
+

steakhal wrote:
> manas wrote:
> > steakhal wrote:
> > > Why do we need this additional condition?
> > > If I remove these, I get no test failures, which suggests to me that we 
> > > have some undertested code paths here.
> > > Why do we need this additional condition?
> > 
> > Bitwidth was important because we should ideally cast smaller bitwidth type 
> > to bigger bitwidth type.
> > 
> > Consider if we have `LHS(u8), RHS(i32)`, then without checking for 
> > bitwidth, we would be casting RHS's maxValue to LHS's type, which will 
> > result in lose of information and will not serve our purpose.
> > 
> > 
> If you think we need that bitwidth check, why did you remove it?
> I'd like to see test cases demonstrating what we are talking about and see if 
> we want that behavior or not.
This test fails.

```

void testfoo(unsigned char u, signed int s) {
  if (u >= 253 && u <= 255 && s < INT_MAX - 2) {
// u: [253, 254], s: [INT_MIN, INT_MAX - 2]
clang_analyzer_eval(u != s); // expected-warning{{UNKNOWN}}
 // but returns TRUE
  }
}
```


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D140086/new/

https://reviews.llvm.org/D140086

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


  1   2   >