https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95000

David Malcolm <dmalcolm at gcc dot gnu.org> 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 <dmalcolm at gcc dot gnu.org> ---
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;

  <bb 2> :
  _1 = (int) x_5(D);
  if (_1 == 98)
    goto <bb 3>; [INV]
  else
    goto <bb 4>; [INV]

  <bb 3> :
<L0>:
  _2 = x_5(D) == 98;
  _3 = (int) _2;
  __analyzer_eval (_3);

  <bb 4> :
<L1>:
  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.

Reply via email to