This change introduces a new component to unite all of the reasoning
we have about operations on ranges in the analyzer's solver.
In many cases, we might conclude that the range for a symbolic operation
is much more narrow than the type implies. While reasoning about
runtime conditions (especially in loops), we need to support more and
more of those little pieces of logic. The new component mostly plays
a role of an organizer for those, and allows us to focus on the actual
reasoning about ranges and not dispatching manually on the types of the
nested symbolic expressions.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Very nice, i like this architecture.
@baloghadamsoftware @steakhal @ASDenysPetrov will you be able to plug D49074/D50256/D77792/D77802/D78933 into this so that to separate algebra from pattern-matching and ensure no performance regressions? Or is something still missing?
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp | ||
---|---|---|
321–331 | Can we replace these three with a single VisitBinarySymExpr()? Or is there too much template duck typing involved? | |
390–395 | I think this is a must-have, at least in some form. We've been exploding like this before on real-world code, well, probably not with bitwise ops but i'm still worried. |
Very nice, i like this architecture.
Aww, thanks 😊
@baloghadamsoftware @steakhal @ASDenysPetrov will you be able to plug D49074/D50256/D77792/D77802/D78933 into this so that to separate algebra from pattern-matching and ensure no performance regressions? Or is something still missing?
Yeah, I'll be happy to hear what will be good to have for all the different cases we have and might have in the future.
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp | ||
---|---|---|
321–331 | Unfortunately no, we need to know more derived types in order to use getLHS and getRHS methods. And that's why VisitBinaryOperator function is a template. | |
390–395 | It will be pretty easy to introduce a limit on how deep we go into a tree of the given symbolic expression. That can also be a solution. |
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp | ||
---|---|---|
390–395 | I mean, doing something super trivial, like defining a map from symexprs to ranges in SymbolicRangeInferrer itself and find-or-inserting into it, will probably not be harder than counting depth(?) |
Now getRange is more likely to return unfeasible range. Calling Intersect and pin methods from such ranges might cause a crash.
Check for unfeasible ranges.
clang/test/Analysis/constant-folding.c | ||
---|---|---|
127–128 | How can both of these be false? o.o |
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp | ||
---|---|---|
390–395 | I am a bit ignorant of this topic, but I wonder what a good caching mechanism would look like. |
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp | ||
---|---|---|
430 | I always get surprised when I read code like the one above seeing that only RHS is tested for being a concerte value. Later on, I vaguely start to remember that we only produce SymIntExprs (is that correct?). I wonder if we should add an assert so this code blows up when someone is trying to add IntSymExprs, so she will know what code needs modification. |
clang/test/Analysis/constant-folding.c | ||
---|---|---|
127–128 | Yeah :) I realized how weird it is. I changed a comment there to address this |
clang/test/Analysis/constant-folding.c | ||
---|---|---|
127–128 | I mean, this pretty much never happened before. How are you not tripping on this assert? (probably it's simply been disabled in normal debug builds now that it's under "expensive checks") The correct thing to do is to detect the paradox earlier and mark the path as infeasible. What prevents us from doing it right away here? |
clang/test/Analysis/constant-folding.c | ||
---|---|---|
127–128 | Before we didn't really care about constraints on the operands and I changed it :) |
clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp | ||
---|---|---|
390–395 | Even a simple symexpr -> range mapping with lifetime of SymbolicRangeInferrer should be able to improve algorithmic complexity dramatically. And it doesn't need to consider different states because it only lives for the duration of a single assume() operation. | |
clang/test/Analysis/constant-folding.c | ||
127–128 | [visible confusion] Could you elaborate? I see that only constraint so far is $a: [11; UINT_MAX]. I don't see any infeasible ranges here. (a & 1) <= 1 is clearly true. If we were previously thinking that it's unknown and now we think that it's false, then it's a regression. |
clang/test/Analysis/constant-folding.c | ||
---|---|---|
127–128 | a is indeed [11, UINT_MAX]. This is why I'm saying that intersection is a bad choice, it's even plain wrong. Yes, it is a regression. I'm changing this implementation in the child revisions. |
clang/test/Analysis/constant-folding.c | ||
---|---|---|
127–128 |
Oh, right, got it :D Ok, let's land 'em together then! |
Can we replace these three with a single VisitBinarySymExpr()? Or is there too much template duck typing involved?