analyzer: fix uninit false +ve due to optimized conditionals [PR102692]
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 11 Feb 2022 21:43:21 +0000 (16:43 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Tue, 15 Feb 2022 21:33:29 +0000 (16:33 -0500)
commit1e2fe6715a949f80c1204ae244baad3cd80ffaf0
treec503a92f3e93bcc196d1e495df99a5d1d73dfb37
parent4d74ea551734694c225643c4069b1b4d4d2b05ed
analyzer: fix uninit false +ve due to optimized conditionals [PR102692]

There is false positive from -Wanalyzer-use-of-uninitialized-value on
gcc.dg/analyzer/pr102692.c here:

  ‘fix_overlays_before’: events 1-3
    |
    |   75 |   while (tail
    |      |          ~~~~
    |   76 |          && (tem = make_lisp_ptr (tail, 5),
    |      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |          |
    |      |          (1) following ‘false’ branch (when ‘tail’ is NULL)...
    |   77 |              (end = marker_position (XOVERLAY (tem)->end)) >= pos))
    |      |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |......
    |   82 |   if (!tail || end < prev || !tail->next)
    |      |       ~~~~~    ~~~~~~~~~~
    |      |       |            |
    |      |       |            (3) use of uninitialized value ‘end’ here
    |      |       (2) ...to here
    |

The issue is that inner || of the conditionals have been folded within the
frontend from a chain of control flow:

   5   │   if (tail == 0B) goto <D.1986>; else goto <D.1988>;
   6   │   <D.1988>:
   7   │   if (end < prev) goto <D.1986>; else goto <D.1989>;
   8   │   <D.1989>:
   9   │   _1 = tail->next;
  10   │   if (_1 == 0B) goto <D.1986>; else goto <D.1987>;
  11   │   <D.1986>:

to an OR expr (and then to a bitwise-or by the gimplifier):

   5   │   _1 = tail == 0B;
   6   │   _2 = end < prev;
   7   │   _3 = _1 | _2;
   8   │   if (_3 != 0) goto <D.1986>; else goto <D.1988>;
   9   │   <D.1988>:
  10   │   _4 = tail->next;
  11   │   if (_4 == 0B) goto <D.1986>; else goto <D.1987>;

This happens for sufficiently simple conditionals in fold_truth_andor.
In particular, the (end < prev) is short-circuited without optimization,
but is evaluated with optimization, leading to the false positive.

Given how early this folding occurs, it seems the simplest fix is to
try to detect places where this optimization appears to have happened,
and suppress uninit warnings within the statement that would have
been short-circuited.

gcc/analyzer/ChangeLog:
PR analyzer/102692
* exploded-graph.h (impl_region_model_context::get_stmt): New.
* region-model.cc: Include "gimple-ssa.h", "tree-phinodes.h",
"tree-ssa-operands.h", and "ssa-iterators.h".
(within_short_circuited_stmt_p): New.
(region_model::check_for_poison): Don't warn about uninit values
if within_short_circuited_stmt_p.
* region-model.h (region_model_context::get_stmt): New vfunc.
(noop_region_model_context::get_stmt): New.

gcc/testsuite/ChangeLog:
PR analyzer/102692
* gcc.dg/analyzer/pr102692-2.c: New test.
* gcc.dg/analyzer/pr102692.c: Remove xfail.  Remove -O2 from
options and move to...
* gcc.dg/analyzer/torture/pr102692.c: ...here.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
gcc/analyzer/exploded-graph.h
gcc/analyzer/region-model.cc
gcc/analyzer/region-model.h
gcc/testsuite/gcc.dg/analyzer/pr102692-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/torture/pr102692.c [moved from gcc/testsuite/gcc.dg/analyzer/pr102692.c with 94% similarity]