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

            Bug ID: 116841
           Summary: [regression gcc 13 -> 14] spurious -Warray-bounds=1
                    warning when resizing + memcpy-ing into vector
           Product: gcc
           Version: 14.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jakob.heher at iaik dot tugraz.at
  Target Milestone: ---

possibly related to 114945 and the issues mentioned therein.

I've tried to distil the minimal reproducible example as much as possible:
https://godbolt.org/z/Kc1bY1e5d

struct StreamWriter {
    private:
        std::vector<uint8_t> _buf;
    public:
        void putBytes(void const* buf, size_t n) {
            size_t const pos = _buf.size();
            _buf.resize(pos+n);
            memcpy(_buf.data()+pos, buf, n);
        }
        void putByte(uint8_t v) { _buf.push_back(v); }
        void putVarint(uint32_t v) {
            if (v <= 0x7f) { putByte(v); }
            else { putByte((v >> 8) | 0x80); putByte(v & 0xff); }
        }
        std::vector<uint8_t> done() { return std::move(_buf); }
};

struct Packet {
    uint32_t packetNumber = 0;
    std::array<uint8_t, 160> destinationConnectionId = {};
    std::array<uint8_t, 160> sourceConnectionId = {};
};

std::vector<uint8_t> encode(Packet const& packet) {
    StreamWriter output;
    output.putVarint(packet.packetNumber);
    output.putBytes(packet.destinationConnectionId.data(),
packet.destinationConnectionId.size());
    output.putBytes(packet.sourceConnectionId.data(),
packet.sourceConnectionId.size());
    return output.done();
}

int main(int, char const**) {
    encode(Packet());
}

Compiling on gcc 14.2.0 using -std=c++20 -g -Wall -Wextra -Werror
-fno-strict-aliasing -fwrapv -O2.

Things that make the bug disappear:
* Switching to -O3. However, the bug can be made to appear at -O3 using a
slightly more complex variant: https://godbolt.org/z/Mr46xTo56
* Removing putVarint, or changing putVarint to always insert a fixed number of
bytes (such as one byte on both branches)
* Removing the second putBytes call
* Manually inlining the function
* Replacing the input to any of the putVarint calls with a predictable value

Compiler output:
In file included from
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/array:43,
                 from <source>:1:
In function 'constexpr typename
__gnu_cxx::__enable_if<std::__is_byte<_Tp>::__value, void>::__type
std::__fill_a1(_Tp*, _Tp*, const _Tp&) [with _Tp = unsigned char]',
    inlined from 'constexpr void std::__fill_a(_FIte, _FIte, const _Tp&) [with
_FIte = unsigned char*; _Tp = unsigned char]' at
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_algobase.h:998:21,
    inlined from 'constexpr _OutputIterator std::__fill_n_a(_OutputIterator,
_Size, const _Tp&, random_access_iterator_tag) [with _OutputIterator = unsigned
char*; _Size = long unsigned int; _Tp = unsigned char]' at
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_algobase.h:1151:20,
    inlined from 'constexpr _OI std::fill_n(_OI, _Size, const _Tp&) [with _OI =
unsigned char*; _Size = long unsigned int; _Tp = unsigned char]' at
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_algobase.h:1180:29,
    inlined from 'static constexpr _ForwardIterator
std::__uninitialized_default_n_1<true>::__uninit_default_n(_ForwardIterator,
_Size) [with _ForwardIterator = unsigned char*; _Size = long unsigned int]' at
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_uninitialized.h:668:29,
    inlined from 'static constexpr _ForwardIterator
std::__uninitialized_default_n_1<true>::__uninit_default_n(_ForwardIterator,
_Size) [with _ForwardIterator = unsigned char*; _Size = long unsigned int]' at
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_uninitialized.h:660:9,
    inlined from 'constexpr _ForwardIterator
std::__uninitialized_default_n(_ForwardIterator, _Size) [with _ForwardIterator
= unsigned char*; _Size = long unsigned int]' at
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_uninitialized.h:712:20,
    inlined from 'constexpr _ForwardIterator
std::__uninitialized_default_n_a(_ForwardIterator, _Size, allocator<_Tp>&)
[with _ForwardIterator = unsigned char*; _Size = long unsigned int; _Tp =
unsigned char]' at
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_uninitialized.h:779:44,
    inlined from 'constexpr void std::vector<_Tp,
_Alloc>::_M_default_append(size_type) [with _Tp = unsigned char; _Alloc =
std::allocator<unsigned char>]' at
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/vector.tcc:821:35,
    inlined from 'constexpr void std::vector<_Tp, _Alloc>::resize(size_type)
[with _Tp = unsigned char; _Alloc = std::allocator<unsigned char>]' at
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_vector.h:1016:21,
    inlined from 'void StreamWriter::putBytes(const void*, size_t)' at
<source>:13:24,
    inlined from 'std::vector<unsigned char> encode(const Packet&)' at
<source>:34:20:
/opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/bits/stl_algobase.h:972:25:
error: 'void* __builtin_memset(void*, int, long unsigned int)' offset [162,
320] is out of the bounds [0, 162] [-Werror=array-bounds=]
  972 |         __builtin_memset(__first, static_cast<unsigned char>(__tmp),
__len);
      |        
~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1plus: all warnings being treated as errors

The bug also occurs in gcc 15.0.0 20240925. The bug does not occur in gcc
13.3.0.
  • [Bug c++/116841] New: [regr... jakob.heher at iaik dot tugraz.at via Gcc-bugs

Reply via email to