https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107852
Bug ID: 107852 Summary: Spurious warnings stringop-overflow and array-bounds copying data as bytes into vector Product: gcc Version: 12.2.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: tree-optimization Assignee: unassigned at gcc dot gnu.org Reporter: cuzdav at gmail dot com Target Milestone: --- Created attachment 53957 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=53957&action=edit preprocessed source code, if that's useful. Starting with gcc 12 and continuing into the current trunk, with optimizations enabled, the compiler emits warnings from static analysis regarding copying data internal to the vector class, both on Compiler Explorer, and on my local linux box running Centos9. Options: g++ warnings.cpp -Werror -O2 -Warray-bounds Code: #include <vector> std::vector<char> bytes; int value{}; void copyValueBytes() { bytes.clear(); auto ptr = reinterpret_cast<const char *>(&value); bytes.insert(bytes.end(), ptr, ptr + sizeof(value)); } https://godbolt.org/z/MfjM9xKjP Observations: * if I don't clear() the vector first, it does not report any errors * if I call bytes.resize(0) it reports the same output * if I call bytes.resize(1) it compiles cleanly * if I use a std::deque instead of a vector, it compiles cleanly A reinterpret_cast always is eye-raising, but I think this is a valid use since its address is casted to a char*, a compatible type. Output: In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/vector:60, from <source>:1: In static member function 'static _Tp* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(const _Tp*, const _Tp*, _Tp*) [with _Tp = char; bool _IsMove = true]', inlined from '_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = true; _II = char*; _OI = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:495:30, inlined from '_OI std::__copy_move_a1(_II, _II, _OI) [with bool _IsMove = true; _II = char*; _OI = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:522:42, inlined from '_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = true; _II = char*; _OI = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:529:31, inlined from '_OI std::copy(_II, _II, _OI) [with _II = move_iterator<char*>; _OI = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:620:7, inlined from 'static _ForwardIterator std::__uninitialized_copy<true>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<char*>; _ForwardIterator = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_uninitialized.h:147:27, inlined from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = move_iterator<char*>; _ForwardIterator = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_uninitialized.h:185:15, inlined from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = move_iterator<char*>; _ForwardIterator = char*; _Tp = char]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_uninitialized.h:372:37, inlined from '_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = char*; _ForwardIterator = char*; _Allocator = allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_uninitialized.h:397:2, inlined from 'void std::vector<_Tp, _Alloc>::_M_range_insert(iterator, _ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const char*; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/vector.tcc:801:9, inlined from 'void std::vector<_Tp, _Alloc>::_M_insert_dispatch(iterator, _InputIterator, _InputIterator, std::__false_type) [with _InputIterator = const char*; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1779:19, inlined from 'std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(const_iterator, _InputIterator, _InputIterator) [with _InputIterator = const char*; <template-parameter-2-2> = void; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1481:22, inlined from 'void copyValueBytes()' at <source>:9:17: /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:431:30: error: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' offset 4 is out of the bounds [0, 4] [-Werror=array-bounds] 431 | __builtin_memmove(__result, __first, sizeof(_Tp) * _Num); | ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:431:30: 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=] In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/x86_64-linux-gnu/bits/c++allocator.h:33, from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/allocator.h:46, from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/vector:61: In member function '_Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = char]', inlined from 'static _Tp* std::allocator_traits<std::allocator<_Tp1> >::allocate(allocator_type&, size_type) [with _Tp = char]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/alloc_traits.h:464:28, inlined from 'std::_Vector_base<_Tp, _Alloc>::pointer std::_Vector_base<_Tp, _Alloc>::_M_allocate(std::size_t) [with _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:378:33, inlined from 'void std::vector<_Tp, _Alloc>::_M_range_insert(iterator, _ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const char*; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/vector.tcc:787:40, inlined from 'void std::vector<_Tp, _Alloc>::_M_insert_dispatch(iterator, _InputIterator, _InputIterator, std::__false_type) [with _InputIterator = const char*; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1779:19, inlined from 'std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(const_iterator, _InputIterator, _InputIterator) [with _InputIterator = const char*; <template-parameter-2-2> = void; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1481:22, inlined from 'void copyValueBytes()' at <source>:9:17: /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:137:55: note: at offset [5, 8] into destination object of size 4 allocated by 'operator new' 137 | return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp))); | ^ cc1plus: all warnings being treated as errors ASM generation compiler returned: 1 In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/vector:60, from <source>:1: In static member function 'static _Tp* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(const _Tp*, const _Tp*, _Tp*) [with _Tp = char; bool _IsMove = true]', inlined from '_OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = true; _II = char*; _OI = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:495:30, inlined from '_OI std::__copy_move_a1(_II, _II, _OI) [with bool _IsMove = true; _II = char*; _OI = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:522:42, inlined from '_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = true; _II = char*; _OI = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:529:31, inlined from '_OI std::copy(_II, _II, _OI) [with _II = move_iterator<char*>; _OI = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:620:7, inlined from 'static _ForwardIterator std::__uninitialized_copy<true>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = std::move_iterator<char*>; _ForwardIterator = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_uninitialized.h:147:27, inlined from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = move_iterator<char*>; _ForwardIterator = char*]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_uninitialized.h:185:15, inlined from '_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, allocator<_Tp>&) [with _InputIterator = move_iterator<char*>; _ForwardIterator = char*; _Tp = char]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_uninitialized.h:372:37, inlined from '_ForwardIterator std::__uninitialized_move_if_noexcept_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = char*; _ForwardIterator = char*; _Allocator = allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_uninitialized.h:397:2, inlined from 'void std::vector<_Tp, _Alloc>::_M_range_insert(iterator, _ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const char*; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/vector.tcc:801:9, inlined from 'void std::vector<_Tp, _Alloc>::_M_insert_dispatch(iterator, _InputIterator, _InputIterator, std::__false_type) [with _InputIterator = const char*; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1779:19, inlined from 'std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(const_iterator, _InputIterator, _InputIterator) [with _InputIterator = const char*; <template-parameter-2-2> = void; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1481:22, inlined from 'void copyValueBytes()' at <source>:9:17: /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:431:30: error: 'void* __builtin_memcpy(void*, const void*, long unsigned int)' offset 4 is out of the bounds [0, 4] [-Werror=array-bounds] 431 | __builtin_memmove(__result, __first, sizeof(_Tp) * _Num); | ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_algobase.h:431:30: 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=] In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/x86_64-linux-gnu/bits/c++allocator.h:33, from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/allocator.h:46, from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/vector:61: In member function '_Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = char]', inlined from 'static _Tp* std::allocator_traits<std::allocator<_Tp1> >::allocate(allocator_type&, size_type) [with _Tp = char]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/alloc_traits.h:464:28, inlined from 'std::_Vector_base<_Tp, _Alloc>::pointer std::_Vector_base<_Tp, _Alloc>::_M_allocate(std::size_t) [with _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:378:33, inlined from 'void std::vector<_Tp, _Alloc>::_M_range_insert(iterator, _ForwardIterator, _ForwardIterator, std::forward_iterator_tag) [with _ForwardIterator = const char*; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/vector.tcc:787:40, inlined from 'void std::vector<_Tp, _Alloc>::_M_insert_dispatch(iterator, _InputIterator, _InputIterator, std::__false_type) [with _InputIterator = const char*; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1779:19, inlined from 'std::vector<_Tp, _Alloc>::iterator std::vector<_Tp, _Alloc>::insert(const_iterator, _InputIterator, _InputIterator) [with _InputIterator = const char*; <template-parameter-2-2> = void; _Tp = char; _Alloc = std::allocator<char>]' at /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/stl_vector.h:1481:22, inlined from 'void copyValueBytes()' at <source>:9:17: /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/new_allocator.h:137:55: note: at offset [5, 8] into destination object of size 4 allocated by 'operator new' 137 | return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp))); | ^ cc1plus: all warnings being treated as errors Execution build compiler returned: 1