[Bug tree-optimization/100366] spurious warning - std::vector::clear followed by std::vector::insert(vec.end(), ...) with -O2

msebor at gcc dot gnu.org gcc-bugzilla@gcc.gnu.org
Mon May 3 17:51:19 GMT 2021


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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |msebor at gcc dot gnu.org

--- Comment #2 from Martin Sebor <msebor at gcc dot gnu.org> ---
The warning is issued during expansion of the memcpy call. It seems fishy that
although it mentions __builtin_memcpy it points to __builtin_memmove:

error: ‘void* __builtin_memcpy(void*, const void*, long unsigned int)’ writing
1 or more bytes into a region of size 0 overflows the destination
[-Werror=stringop-overflow=]
  431 |             __builtin_memmove(__result, __first, sizeof(_Tp) * _Num);
      |             ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The IL looks like the warning is justified:

void func (struct vector & vec)
{
  const ptrdiff_t _Num;
  char * _6;
  char * _7;
  char * prephitmp_16;
  char * _21;
  long int _23;
  long unsigned int _24;
  sizetype prephitmp_31;
  char * _36;
  char * _38;
  char * prephitmp_42;
  char * _50;
  long unsigned int _Num.10_52;
  char * _54;
  char * _61;
  char * pretmp_67;
  long int _69;
  char * pretmp_70;
  long int _71;
  unsigned int pretmp_72;
  unsigned int _89;
  char * _90;
  char * _98;
  char * _101;
  long unsigned int _112;
  char * _116;
  long unsigned int _144;
  long int _146;
  char * _147;
  char * _155;
  sizetype _157;
  char * _158;

  <bb 2> [local count: 1073741824]:
  _6 = vec_2(D)->D.33449._M_impl.D.32762._M_start;
  _7 = vec_2(D)->D.33449._M_impl.D.32762._M_finish;
  if (_6 != _7)
    goto <bb 4>; [70.00%]
  else
    goto <bb 3>; [30.00%]

  <bb 3> [local count: 322122544]:
  _21 = vec_2(D)->D.33449._M_impl.D.32762._M_end_of_storage;
  _23 = _21 - _7;
  _24 = (long unsigned int) _23;
  if (_24 > 3)
    goto <bb 5>; [67.00%]
  else
    goto <bb 13>; [33.00%]

  <bb 4> [local count: 751619281]:
  vec_2(D)->D.33449._M_impl.D.32762._M_finish = _6;
  _147 = vec_2(D)->D.33449._M_impl.D.32762._M_end_of_storage;
  _146 = _147 - _6;
  _144 = (long unsigned int) _146;
  if (_144 > 3)
    goto <bb 5>; [67.00%]
  else
    goto <bb 13>; [33.00%]

  <bb 5> [local count: 237404317]:
  # prephitmp_16 = PHI <_7(3), _6(4)>
  _89 = MEM <unsigned int> [(char * {ref-all})&UTC];
  MEM <unsigned int> [(char * {ref-all})prephitmp_16] = _89;
  _36 = vec_2(D)->D.33449._M_impl.D.32762._M_finish;
  _38 = _36 + 4;
  vec_2(D)->D.33449._M_impl.D.32762._M_finish = _38;
  goto <bb 12>; [100.00%]

  <bb 6> [local count: 108584968]:
  __builtin_memmove (_90, pretmp_67, _157);
  MEM <unsigned int> [(char * {ref-all})_155] = pretmp_72;
  _116 = vec_2(D)->D.33449._M_impl.D.32762._M_finish;
  _Num_117 = _116 - prephitmp_42;
  if (_Num_117 != 0)
    goto <bb 8>; [33.00%]                             >>> _Num_117 != 0
  else
    goto <bb 10>; [67.00%]

  <bb 7> [local count: 220460391]:
  MEM <unsigned int> [(char * {ref-all})_155] = pretmp_72;
  _50 = vec_2(D)->D.33449._M_impl.D.32762._M_finish;
  _Num_51 = _50 - prephitmp_42;
  if (_Num_51 != 0)
    goto <bb 8>; [33.00%]                             >>> _Num_51 != 0
  else
    goto <bb 9>; [67.00%]

  <bb 8> [local count: 108584968]:
  # _Num_119 = PHI <_Num_51(7), _Num_117(6)>          <<< _Num_119 != 0
  _Num.10_52 = (long unsigned int) _Num_119;
  __builtin_memcpy (_61, prephitmp_42, _Num.10_52);   <<< -Wstringop-overflow

  <bb 9> [local count: 256293430]:
  # prephitmp_31 = PHI <0(7), _Num.10_52(8)>
  _54 = _61 + prephitmp_31;
  if (pretmp_67 != 0B)
    goto <bb 10>; [40.26%]
  else
    goto <bb 11>; [59.74%]

  <bb 10> [local count: 175940553]:
  # _98 = PHI <_54(9), _61(6)>
  _71 = pretmp_70 - pretmp_67;
  _112 = (long unsigned int) _71;
  operator delete (pretmp_67, _112);

  <bb 11> [local count: 329045359]:
  # _101 = PHI <_54(9), _98(10)>
  vec_2(D)->D.33449._M_impl.D.32762._M_start = _90;
  vec_2(D)->D.33449._M_impl.D.32762._M_finish = _101;
  vec_2(D)->D.33449._M_impl.D.32762._M_end_of_storage = _158;

  <bb 12> [local count: 1048452384]:
  return;

  <bb 13> [local count: 230225493]:
  # prephitmp_42 = PHI <_6(4), _7(3)>
  _90 = operator new (4);                             <<< _90 is 4 bytes
  pretmp_67 = vec_2(D)->D.33449._M_impl.D.32762._M_start;
  _69 = prephitmp_42 - pretmp_67;
  _157 = (sizetype) _69;
  _158 = _90 + 4;
  pretmp_70 = vec_2(D)->D.33449._M_impl.D.32762._M_end_of_storage;
  _155 = _90 + _157;                                  <<< _155 is in [_90, _90
+ 4]
  _61 = _155 + 4;                                     <<< _61 = _90 + 4
  pretmp_72 = MEM <unsigned int> [(char * {ref-all})&UTC];
  if (_69 != 0)
    goto <bb 6>; [58.89%]
  else
    goto <bb 7>; [41.11%]

}


In the translation unit the warning is triggered by a call to the __copy_m()
function below:

  template<bool _IsMove>
    struct __copy_move<_IsMove, true, random_access_iterator_tag>
    {
      template<typename _Tp>

 static _Tp*
 __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result)
 {

   using __assignable = conditional<_IsMove,
        is_move_assignable<_Tp>,
        is_copy_assignable<_Tp>>;

   static_assert( __assignable::type::value, "type is not assignable" );

   const ptrdiff_t _Num = __last - __first;
   if (_Num)
     __builtin_memmove(__result, __first, sizeof(_Tp) * _Num);
   return __result + _Num;
 }
    };


The test for _Num is what GCC uses to determine that the number of bytes to
copy is nonzero.


More information about the Gcc-bugs mailing list