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

Manas Gupta via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Thu Jun 3 19:23:07 PDT 2021


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



More information about the cfe-commits mailing list