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.