[cfe-dev] PR16833 - Analyzer hangs trying to analyze large case ranges

Jordan Rose jordan_rose at apple.com
Tue Aug 12 19:38:37 PDT 2014

That FIXME, and indeed the code to support case ranges, actually predates RangeConstraintManager, which implements most of what the FIXME is referring to. (That is, the technical/historical reason we couldn't do it symbolically is "it wasn't implemented yet".) So your change is in fact on the right track.

However, what you've done is construct the expression "$x >= LOWER && $x <= UPPER". This is correct, but it's not a form that RangeConstraintManager will actually handle right now:

void clang_analyzer_eval(int);
void test(int i) {
	switch (i) {
	case 1 ... 5:
	clang_analyzer_eval(x == 2); // should print FALSE, but will print UNKNOWN with your patch.

(clang_analyzer_eval is a special function used to probe the analyzer state, handled by the debug.ExprInspection checker.)

The easiest way to fix this would be to use assumeDual on each expression individually. Then you end up with three cases: $x < LOWER, $x is in range, and $x > UPPER. Unfortunately, you'd then have to restructure the whole function, which currently assumes that you end up with exactly one state that can end up in the "default" branch. That wouldn't be too hard.

The harder way to solve this is to actually teach [Range]ConstraintManager to recognize constraints like this, and do the right thing. The implementation is already set up to handle disjoint sets of ranges, so you could actually do this without changing everything. It's probably more messy than you'd like, though.

The sneaky way to do this is to realize that "$x >= LOWER && $x <= UPPER" is actually equivalent to "$x - (LOWER - MIN) <= UPPER - (LOWER - MIN)", where MIN is the minimum value for the integer type, for integers with wraparound semantics. (RangeConstraintManager actually takes advantage of this in reverse to translate "$x - OFFSET <= VALUE" back into a pair of range disjunctions.) The only trouble with doing something like this is that wraparound is Hardâ„¢ and you/we will want to be very careful that this actually handles everything correctly, for all the integer types we care about. A definite benefit of this is that we're back to only having one state, which prevents potential exponential explosion as analysis continues.

What do you think we should do here?

On Aug 12, 2014, at 12:39 , Zach Davis <zdavkeos at gmail.com> wrote:

> All-
> I was looking over 16833 and had a few questions.
> The issue is the analyzer tries to concretize all the values in a case
> statement with a range value:
>    switch (a) {
>        case 1 ... 0xfffff: // hang's trying each value in the range
>           return 1;
>        default:
>           return 0;
>    }
> Is there any reason we can't symbolically evaluate 1 <= a <= 0xfffff,
> rather than trying each 'a == v for v in 1..0xfffff'? I've attached a
> patch that attempts to do this and it seems to work (it no longer
> hangs anyway).  Is there a technical/historical reason for doing it
> the current way?
> The FIXME above the block mentions using '"ranges" for NonLVals'. I'm
> not sure what this means, or if any work has been done toward this.
> If not, would there be any value in pursing a patch like this in the
> meantime to resolve the performance issue?
> Thanks,
> Zach
> <16833_hang_on_large_case_range.patch>_______________________________________________
> cfe-dev mailing list
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20140812/982617f2/attachment.html>

More information about the cfe-dev mailing list