[Bug tree-optimization/107852] New: Spurious warnings stringop-overflow and array-bounds copying data as bytes into vector

cuzdav at gmail dot com gcc-bugzilla@gcc.gnu.org
Wed Nov 23 23:24:13 GMT 2022


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


More information about the Gcc-bugs mailing list