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

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|WAITING                     |NEW
                 CC|                            |amacleod at redhat dot com

--- Comment #8 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Kees Cook from comment #7)
> (In reply to Kees Cook from comment #6)
> > Sorry, I forgot to include those details fully! Here's how I'm seeing it:
> > 
> > $ gcc --version
> > gcc (GCC) 13.0.0 20230105 (experimental)
> > ...
> > $ gcc -O2 -fno-strict-overflow -fsanitize=shift -Warray-bounds -c -o
> > /dev/null poc.c
> 
> In function 'psi_group_change',
>     inlined from 'psi_task_switch' at poc.c:25:2:
> poc.c:15:30: warning: array subscript 32 is above array bounds of 'unsigned
> int[4]' [-Warray-bounds=]
>    15 |                         tasks[t]++;
>       |                         ~~~~~^~~
> poc.c: In function 'psi_task_switch':
> poc.c:6:14: note: while referencing 'tasks'
>     6 | unsigned int tasks[NR_PSI_TASK_COUNTS];
>       |              ^~~~~
> 
> (mispaste)

we diagnose

<bb 5> [local count: 8687547547]:
if (t_6 > 31)
  goto <bb 9>; [0.00%]

<bb 9> [count: 0]:
_7 = (unsigned long) t_6;
__builtin___ubsan_handle_shift_out_of_bounds (&*.Lubsan_data1, 1, _7);
_8 = 1 << t_6;
_9 = (unsigned int) _8;
_35 = _8 & 1;
_11 = (unsigned int) _35;
if (_35 != 0)
  goto <bb 10>; [50.00%]

<bb 10> [local count: 0]:
_12 = tasks[t_6];
_13 = _12 + 1;
tasks[t_6] = _13;

clearly t_6 is > 31 and thus the access is out-of-bounds [in the IL].
What we miss is the fact that we can rely on t_6 being in bounds for
the 1 << t_6 shift and thus this is unreachable code plus the fact
that for 1 << t_6 with t_6 > 31 bit zero is always zero.  That's something
for ranger to see - why doesn't it?  We have

=========== BB 5 ============
Imports: t_6
Exports: t_6
t_6     [irange] unsigned int VARYING
    <bb 5> [local count: 8687547547]:
    if (t_6 > 31)
      goto <bb 9>; [0.00%]
    else
      goto <bb 6>; [100.00%]

5->9  (T) t_6 :         [irange] unsigned int [32, +INF]
5->6  (F) t_6 :         [irange] unsigned int [0, 31] NONZERO 0x1f

=========== BB 9 ============
Imports: t_6  set_10
Exports: t_6  _8  _9  set_10  _11
         _7 : t_6(I)
         _8 : t_6(I)
         _9 : t_6(I)  _8
         _11 : t_6(I)  _8  _9  set_10(I)
         _35 : t_6(I)  _8
t_6     [irange] unsigned int [32, +INF]
set_10  [irange] unsigned int [1, 1] NONZERO 0x1
Partial equiv (_7 pe32 t_6)
Partial equiv (_9 pe32 _8)
    <bb 9> [count: 0]:
    _7 = (unsigned long) t_6;
    __builtin___ubsan_handle_shift_out_of_bounds (&*.Lubsan_data1, 1, _7);
    _8 = 1 << t_6;
    _9 = (unsigned int) _8;
    _35 = _8 & 1;
    _11 = (unsigned int) _35;
    if (_35 != 0)
      goto <bb 10>; [50.00%]
      goto <bb 10>; [50.00%]
    else
      goto <bb 11>; [50.00%]

_7 : [irange] unsigned long [32, 4294967295] NONZERO 0xffffffff
_11 : [irange] unsigned int [0, 1] NONZERO 0x1
9->10  (T) t_6 :        [irange] unsigned int [32, +INF]
9->10  (T) _7 :         [irange] unsigned long [32, 4294967295] NONZERO
0xffffffff
9->10  (T) _8 :         [irange] int [-INF, -1][1, +INF]
9->10  (T) set_10 :     [irange] unsigned int [1, 1] NONZERO 0x1
9->10  (T) _11 :        [irange] unsigned int [0, 1] NONZERO 0x1
9->10  (T) _35 :        [irange] int [0, 1] NONZERO 0x1
9->11  (F) t_6 :        [irange] unsigned int [32, +INF]
9->11  (F) _7 :         [irange] unsigned long [32, 4294967295] NONZERO
0xffffffff
9->11  (F) _8 :         [irange] int [-INF, -2][0, +INF] NONZERO 0xfffffffe
9->11  (F) set_10 :     [irange] unsigned int [1, 1] NONZERO 0x1
9->11  (F) _11 :        [irange] unsigned int [0, 1] NONZERO 0x1
9->11  (F) _35 :        [irange] int [0, 0] NONZERO 0x0

even without -fwrapv we don't seem to know that 1 << [32, +INF] resolves
to zero?!

6->7  (T) _31 :         [irange] int [-INF, -1][1, +INF]
6->8  (F) _31 :         [irange] int [-INF, -2][0, +INF] NONZERO 0xfffffffe

we seem to fall into

  else
    // Otherwise, invoke the generic fold routine.
    return range_operator::fold_range (r, type, op1, shift_range, rel);

and that oddly enough receives

(gdb) p debug (rh)
[irange] unsigned int [0, 31] NONZERO 0x1f

?!

#0  range_operator::fold_range (this=0x42f4ef0 <op_lshift>, r=..., 
    type=<integer_type 0x7ffff62855e8 int>, lh=..., rh=..., trio=...)
    at /home/rguenther/src/trunk/gcc/range-op.cc:244
#1  0x0000000002e26152 in operator_lshift::fold_range (
    this=0x42f4ef0 <op_lshift>, r=..., type=<integer_type 0x7ffff62855e8 int>, 
    op1=..., op2=..., rel=...)
    at /home/rguenther/src/trunk/gcc/range-op.cc:2192
#2  0x0000000002e3043d in range_op_handler::fold_range (this=0x7fffffff2c90, 
    r=..., type=<integer_type 0x7ffff62855e8 int>, lh=..., rh=..., rel=...)
    at /home/rguenther/src/trunk/gcc/range-op.cc:4506
#3  0x0000000002cb07e2 in fold_using_range::range_of_range_op (
    this=0x7fffffff2d3f, r=..., handler=..., src=...)
    at /home/rguenther/src/trunk/gcc/gimple-range-fold.cc:589
#4  0x0000000002caff11 in fold_using_range::fold_stmt (this=0x7fffffff2d3f, 
    r=..., s=<gimple_assign 0x7ffff607e630>, src=..., 
    name=<ssa_name 0x7ffff607cc18 8>)
    at /home/rguenther/src/trunk/gcc/gimple-range-fold.cc:489
#5  0x0000000002caf425 in fold_range (r=..., s=<gimple_assign 0x7ffff607e630>, 
    on_edge=<edge 0x7ffff60842d0 (11 -> 13)>, q=0x4352c88)
    at /home/rguenther/src/trunk/gcc/gimple-range-fold.cc:326
#6  0x0000000002cb89d0 in gori_compute::outgoing_edge_range_p (this=0x4352ca0, 
    r=..., e=<edge 0x7ffff60842d0 (11 -> 13)>, 
    name=<ssa_name 0x7ffff607cc18 8>, q=...)
    at /home/rguenther/src/trunk/gcc/gimple-range-gori.cc:1400
#7  0x0000000002ca8193 in ranger_cache::edge_range (this=0x4352c88, r=..., 
    e=<edge 0x7ffff60842d0 (11 -> 13)>, name=<ssa_name 0x7ffff607cc18 8>, 
    mode=ranger_cache::RFD_NONE)
    at /home/rguenther/src/trunk/gcc/gimple-range-cache.cc:964
#8  0x0000000002ca831c in ranger_cache::range_on_edge (this=0x4352c88, r=..., 
    e=<edge 0x7ffff60842d0 (11 -> 13)>, expr=<ssa_name 0x7ffff607cc18 8>)
    at /home/rguenther/src/trunk/gcc/gimple-range-cache.cc:1001
#9  0x0000000002ca256f in gimple_ranger::range_on_edge (this=0x4352c60, r=..., 
    e=<edge 0x7ffff60842d0 (11 -> 13)>, name=<ssa_name 0x7ffff607cc18 8>)
    at /home/rguenther/src/trunk/gcc/gimple-range.cc:241
#10 0x0000000002caedc8 in fur_edge::get_operand (this=0x7fffffff6030, r=..., 
    expr=<ssa_name 0x7ffff607cc18 8>)
    at /home/rguenther/src/trunk/gcc/gimple-range-fold.cc:131
#11 0x0000000002caeefc in fur_stmt::get_phi_operand (this=0x7fffffff9350, 
    r=..., expr=<ssa_name 0x7ffff607cc18 8>, 
    e=<edge 0x7ffff60842d0 (11 -> 13)>)
    at /home/rguenther/src/trunk/gcc/gimple-range-fold.cc:168
...

maybe I didn't capture the "correct" call (there are too many).  Still
something
goes wrong here.

A small testcase like

int foo (int n)
{
  if (n > 31)
    {
      int tem = 1 << n;
      if ((unsigned)tem & 1)
        bar ();
    }
}

is optimized just fine.

Reply via email to