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

Martin Sebor <msebor at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Blocks|                            |97048
             Status|UNCONFIRMED                 |NEW
     Ever confirmed|0                           |1
   Last reconfirmed|                            |2021-05-11
      Known to work|                            |10.3.0
            Summary|Unexpected                  |[11 Regression] Unexpected
                   |-Wstringop-overread in      |-Wstringop-overread in
                   |deque<char> initialization  |deque<char> initialization
                   |from empty initializer_list |from empty initializer_list
      Known to fail|                            |11.1.0, 12.0

--- Comment #3 from Martin Sebor <msebor at gcc dot gnu.org> ---
Confirmed.  Strictly speaking it's a GCC 11 regression introduced by a) the
warning becoming stricter and considering constant addresses to be invalid (as
they usually result from invalid arithmetic involving null pointers), and b)
GCC 11 exposing the null pointer arithmetic.  The warning in the original test
case in comment #0 triggers for the IL below where _19 is set to the address
512 plus some offset:

  <bb 5> [local count: 955247968]:
  _18 = (unsigned long) _58;
  _67 = (unsigned long) __cur_node_17;
  _13 = _18 + 18446744073709551615;
  _40 = _13 - _67;
  _25 = _40 >> 3;
  _3 = _25 * 512;
  _19 = 512B + _3;                          <<< 512 (invalid address)
  _26 = D.17216.D.17192._M_impl.D.16554._M_finish._M_first;
  _39 = (long int) _19;
  _Num_28 = -_39;
  _Num.7_29 = (long unsigned int) _Num_28;  <<< nonzero
  __builtin_memcpy (_26, _19, _Num.7_29);   <<< -Wstringop-overread

Since there can be no object at address 512 its size is determined to be zero. 
The warning triggers because the third argument to memcpy is determined to be
nonzero (also 512 plus some offset).  The bad address results from SCCP:

final value replacement:
  _19 = PHI <_37(4)>
 with expr: 512B + ((((unsigned long) _58 - (unsigned long) __cur_node_17) +
18446744073709551615) / 8) * 512
 final stmt:
  _19 = 512B + _3;

based on:

  <bb 4> [local count: 8684072504]:
  # __first_2 = PHI <_37(10), 0B(9)>
  # __cur_node_42 = PHI <__cur_node_24(10), __cur_node_17(9)>
  _37 = __first_2 + 512;

The underlying problem is that the loop in deque::_M_range_initialize()
iterates over both the deque's nodes and the initializer list's elements, and
the number of iterations has no apparent relationship to the latter.  As far as
GCC sees, the loop increments the null pointer to the empty initializer list by
the deque's buffer size of 512.  The warning could be avoided by
_M_range_initialize() returning early, before entering the loop, when the range
is empty.  Alternatively, it could be suppressed by #pragma GCC diagnostic
(that might need a patch like the one mentioned in pr98465 comment 32).


Referenced Bugs:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97048
[Bug 97048] [meta-bug] bogus/missing -Wstringop-overread warnings

Reply via email to