https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95000
David Malcolm changed:
What|Removed |Added
Ever confirmed|0 |1
Status|UNCONFIRMED |ASSIGNED
Last reconfirmed||2020-05-08
Summary|-fanalyzer confused by |-fanalyzer confused by
|switch |switch on non-int type
--- Comment #4 from David Malcolm ---
This turns out to be a problem with tracking path-conditions with casts.
Switch statements on a non-int type (such as char) have an implicit cast to int
and trigger the issue.
Consider this test case, using the not-quite-a-builtin "__analyzer_eval" to
evaluate a condition. In each case we expect __analyzer_eval to emit "TRUE":
--
extern void __analyzer_eval (int);
void test_switch_char(char x) {
switch (x) {
case 'b':
__analyzer_eval (x == 'b');
}
}
void test_switch_int(int x) {
switch (x) {
case 97:
__analyzer_eval (x == 97);
}
}
void test_if_char(char x) {
if (x == 'b')
__analyzer_eval (x == 'b');
}
void test_if_int(int x) {
if (x == 97)
__analyzer_eval (x == 97);
}
--
I get this output (note that the output is in reverse order):
s.c: In function ‘test_if_int’:
s.c:24:5: warning: TRUE
24 | __analyzer_eval (x == 97);
| ^
s.c: In function ‘test_if_char’:
s.c:19:5: warning: TRUE
19 | __analyzer_eval (x == 'b');
| ^~
s.c: In function ‘test_switch_int’:
s.c:13:5: warning: TRUE
13 | __analyzer_eval (x == 97);
| ^
s.c: In function ‘test_switch_char’:
s.c:6:5: warning: UNKNOWN
6 | __analyzer_eval (x == 'b');
| ^~
where we get it wrong for test_switch_char.
At the gimple level, we have:
test_switch_char (char x)
{
int _1;
_Bool _2;
int _3;
:
_1 = (int) x_5(D);
if (_1 == 98)
goto ; [INV]
else
goto ; [INV]
:
:
_2 = x_5(D) == 98;
_3 = (int) _2;
__analyzer_eval (_3);
:
:
return;
}
The cast here:
_1 = (int) x_5(D);
if (_1 == 98)
seems to thwart my constraint-tracking.
If I use -fno-analyzer-state-purge it at least "knows" that _1 == 98 within the
"case" BB.
I'm working on a rewrite of state-tracking for GCC 11 that ought to better
handle casts.