New array-bounds and stringop-overflow GCC 13 warnings in spdlog+gtest program

295 views Asked by At

I updated the operating system from Fedora 37 to Fedora 38, and my program started to produce new compilation warnings: array-bounds and stringop-overflow. The program depends on the libraries from the standard packages coming with the operating system, which in Fedora 38 are

  • spdlog v1.11
  • fmt v9.1
  • gtest v1.13

and is compiled with Fedora 38's standard GCC 13.2.1.

After the simplification I managed to get the following minimal example:

#include <spdlog/spdlog.h>
#include <gtest/gtest.h>

TEST( a, b ) {
    spdlog::info( "info {}", 1 );
}

which if compiled with the flags -Wall -Werror -pedantic-errors shows

In file included from /usr/include/c++/13/string:51,
                 from /usr/include/c++/13/bits/locale_classes.h:40,
                 from /usr/include/c++/13/bits/ios_base.h:41,
                 from /usr/include/c++/13/ios:44,
                 from /usr/include/c++/13/istream:40,
                 from /usr/include/c++/13/sstream:40,
                 from /usr/include/c++/13/chrono:45,
                 from /usr/include/spdlog/common.h:10,
                 from /usr/include/spdlog/spdlog.h:12,
                 from test.cpp:3:
In static member function 'static constexpr _Up* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(_Tp*, _Tp*, _Up*) [with _Tp = unsigned int; _Up = unsigned int; bool _IsMove = false]',
    inlined from 'constexpr _OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = unsigned int*; _OI = unsigned int*]' at /usr/include/c++/13/bits/stl_algobase.h:506:30,
    inlined from 'constexpr _OI std::__copy_move_a1(_II, _II, _OI) [with bool _IsMove = false; _II = unsigned int*; _OI = unsigned int*]' at /usr/include/c++/13/bits/stl_algobase.h:533:42,
    inlined from 'constexpr _OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = unsigned int*; _OI = unsigned int*]' at /usr/include/c++/13/bits/stl_algobase.h:540:31,
    inlined from 'constexpr _OI std::copy(_II, _II, _OI) [with _II = unsigned int*; _OI = unsigned int*]' at /usr/include/c++/13/bits/stl_algobase.h:633:7,
    inlined from 'static _ForwardIterator std::__uninitialized_copy<true>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = unsigned int*; _ForwardIterator = unsigned int*]' at /usr/include/c++/13/bits/stl_uninitialized.h:147:27,
    inlined from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = unsigned int*; _ForwardIterator = unsigned int*]' at /usr/include/c++/13/bits/stl_uninitialized.h:185:15,
    inlined from 'constexpr void fmt::v9::basic_memory_buffer<T, SIZE, Allocator>::grow(size_t) [with T = unsigned int; long unsigned int SIZE = 32; Allocator = std::allocator<unsigned int>]' at /usr/include/fmt/format.h:925:26,
    inlined from 'constexpr void fmt::v9::detail::buffer<T>::try_reserve(size_t) [with T = unsigned int]' at /usr/include/fmt/core.h:928:39,
    inlined from 'constexpr void fmt::v9::detail::buffer<T>::try_resize(size_t) [with T = unsigned int]' at /usr/include/fmt/core.h:919:16,
    inlined from 'constexpr void fmt::v9::basic_memory_buffer<T, SIZE, Allocator>::resize(size_t) [with T = unsigned int; long unsigned int SIZE = 32; Allocator = std::allocator<unsigned int>]' at /usr/include/fmt/format.h:897:63,
    inlined from 'constexpr void fmt::v9::detail::bigint::assign(UInt) [with UInt = long unsigned int; typename std::enable_if<(std::is_same<UInt, long unsigned int>::value || std::is_same<UInt, __int128 unsigned>::value), int>::type <anonymous> = 0]' at /usr/include/fmt/format.h:2792:19,
    inlined from 'constexpr void fmt::v9::detail::bigint::operator=(Int) [with Int = int]' at /usr/include/fmt/format.h:2813:11,
    inlined from 'constexpr void fmt::v9::detail::bigint::assign_pow10(int)' at /usr/include/fmt/format.h:2893:11,
    inlined from 'constexpr void fmt::v9::detail::bigint::assign_pow10(int)' at /usr/include/fmt/format.h:2884:24,
    inlined from 'constexpr void fmt::v9::detail::format_dragon(basic_fp<__int128 unsigned>, unsigned int, int, buffer<char>&, int&)' at /usr/include/fmt/format.h:3011:29:
/usr/include/c++/13/bits/stl_algobase.h:437:30: error: 'void* __builtin_memmove(void*, const void*, long unsigned int)' forming offset 4 is out of the bounds [0, 4] [-Werror=array-bounds=]
  437 |             __builtin_memmove(__result, __first, sizeof(_Tp) * _Num);
      |             ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

If I silence the first warning with #pragma GCC diagnostic ignored "-Warray-bounds", then another one appears:

In file included from /usr/include/c++/13/string:51,
                 from /usr/include/c++/13/bits/locale_classes.h:40,
                 from /usr/include/c++/13/bits/ios_base.h:41,
                 from /usr/include/c++/13/ios:44,
                 from /usr/include/c++/13/istream:40,
                 from /usr/include/c++/13/sstream:40,
                 from /usr/include/c++/13/chrono:45,
                 from /usr/include/spdlog/common.h:10,
                 from /usr/include/spdlog/spdlog.h:12,
                 from test.cpp:7:
In static member function 'static constexpr _Up* std::__copy_move<_IsMove, true, std::random_access_iterator_tag>::__copy_m(_Tp*, _Tp*, _Up*) [with _Tp = unsigned int; _Up = unsigned int; bool _IsMove = false]',
    inlined from 'constexpr _OI std::__copy_move_a2(_II, _II, _OI) [with bool _IsMove = false; _II = unsigned int*; _OI = unsigned int*]' at /usr/include/c++/13/bits/stl_algobase.h:506:30,
    inlined from 'constexpr _OI std::__copy_move_a1(_II, _II, _OI) [with bool _IsMove = false; _II = unsigned int*; _OI = unsigned int*]' at /usr/include/c++/13/bits/stl_algobase.h:533:42,
    inlined from 'constexpr _OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = false; _II = unsigned int*; _OI = unsigned int*]' at /usr/include/c++/13/bits/stl_algobase.h:540:31,
    inlined from 'constexpr _OI std::copy(_II, _II, _OI) [with _II = unsigned int*; _OI = unsigned int*]' at /usr/include/c++/13/bits/stl_algobase.h:633:7,
    inlined from 'static _ForwardIterator std::__uninitialized_copy<true>::__uninit_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = unsigned int*; _ForwardIterator = unsigned int*]' at /usr/include/c++/13/bits/stl_uninitialized.h:147:27,
    inlined from '_ForwardIterator std::uninitialized_copy(_InputIterator, _InputIterator, _ForwardIterator) [with _InputIterator = unsigned int*; _ForwardIterator = unsigned int*]' at /usr/include/c++/13/bits/stl_uninitialized.h:185:15,
    inlined from 'constexpr void fmt::v9::basic_memory_buffer<T, SIZE, Allocator>::grow(size_t) [with T = unsigned int; long unsigned int SIZE = 32; Allocator = std::allocator<unsigned int>]' at /usr/include/fmt/format.h:925:26,
    inlined from 'constexpr void fmt::v9::detail::buffer<T>::try_reserve(size_t) [with T = unsigned int]' at /usr/include/fmt/core.h:928:39,
    inlined from 'constexpr void fmt::v9::detail::buffer<T>::try_resize(size_t) [with T = unsigned int]' at /usr/include/fmt/core.h:919:16,
    inlined from 'constexpr void fmt::v9::basic_memory_buffer<T, SIZE, Allocator>::resize(size_t) [with T = unsigned int; long unsigned int SIZE = 32; Allocator = std::allocator<unsigned int>]' at /usr/include/fmt/format.h:897:63,
    inlined from 'constexpr void fmt::v9::detail::bigint::assign(UInt) [with UInt = long unsigned int; typename std::enable_if<(std::is_same<UInt, long unsigned int>::value || std::is_same<UInt, __int128 unsigned>::value), int>::type <anonymous> = 0]' at /usr/include/fmt/format.h:2792:19,
    inlined from 'constexpr void fmt::v9::detail::bigint::operator=(Int) [with Int = int]' at /usr/include/fmt/format.h:2813:11,
    inlined from 'constexpr void fmt::v9::detail::bigint::assign_pow10(int)' at /usr/include/fmt/format.h:2893:11,
    inlined from 'constexpr void fmt::v9::detail::bigint::assign_pow10(int)' at /usr/include/fmt/format.h:2884:24,
    inlined from 'constexpr void fmt::v9::detail::format_dragon(basic_fp<__int128 unsigned>, unsigned int, int, buffer<char>&, int&)' at /usr/include/fmt/format.h:3011:29:
/usr/include/c++/13/bits/stl_algobase.h:437:30: error: 'void* __builtin_memmove(void*, const void*, long unsigned int)' writing between 5 and 9223372036854775807 bytes into a region of size 4 overflows the destination [-Werror=stringop-overflow=]
  437 |             __builtin_memmove(__result, __first, sizeof(_Tp) * _Num);
      |             ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/c++/13/x86_64-redhat-linux/bits/c++allocator.h:33,
                 from /usr/include/c++/13/bits/allocator.h:46,
                 from /usr/include/c++/13/string:43:
In member function '_Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = unsigned int]',
    inlined from 'constexpr _Tp* std::allocator< <template-parameter-1-1> >::allocate(std::size_t) [with _Tp = unsigned int]' at /usr/include/c++/13/bits/allocator.h:198:40,
    inlined from 'static constexpr _Tp* std::allocator_traits<std::allocator<_CharT> >::allocate(allocator_type&, size_type) [with _Tp = unsigned int]' at /usr/include/c++/13/bits/alloc_traits.h:482:28,
    inlined from 'constexpr void fmt::v9::basic_memory_buffer<T, SIZE, Allocator>::grow(size_t) [with T = unsigned int; long unsigned int SIZE = 32; Allocator = std::allocator<unsigned int>]' at /usr/include/fmt/format.h:923:49,
    inlined from 'constexpr void fmt::v9::detail::buffer<T>::try_reserve(size_t) [with T = unsigned int]' at /usr/include/fmt/core.h:928:39,
    inlined from 'constexpr void fmt::v9::detail::buffer<T>::try_resize(size_t) [with T = unsigned int]' at /usr/include/fmt/core.h:919:16,
    inlined from 'constexpr void fmt::v9::basic_memory_buffer<T, SIZE, Allocator>::resize(size_t) [with T = unsigned int; long unsigned int SIZE = 32; Allocator = std::allocator<unsigned int>]' at /usr/include/fmt/format.h:897:63,
    inlined from 'constexpr void fmt::v9::detail::bigint::assign(UInt) [with UInt = long unsigned int; typename std::enable_if<(std::is_same<UInt, long unsigned int>::value || std::is_same<UInt, __int128 unsigned>::value), int>::type <anonymous> = 0]' at /usr/include/fmt/format.h:2792:19,
    inlined from 'constexpr void fmt::v9::detail::bigint::operator=(Int) [with Int = int]' at /usr/include/fmt/format.h:2813:11,
    inlined from 'constexpr void fmt::v9::detail::bigint::assign_pow10(int)' at /usr/include/fmt/format.h:2893:11,
    inlined from 'constexpr void fmt::v9::detail::bigint::assign_pow10(int)' at /usr/include/fmt/format.h:2884:24,
    inlined from 'constexpr void fmt::v9::detail::format_dragon(basic_fp<__int128 unsigned>, unsigned int, int, buffer<char>&, int&)' at /usr/include/fmt/format.h:3011:29:
/usr/include/c++/13/bits/new_allocator.h:147:55: note: destination object of size 4 allocated by 'operator new'
  147 |         return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
      |                                                 

Unfortunetly, I cannot reproduce it in online compiler godbolt.org because it lacks exactly the same versions of the libraries.

I guess that the problem is in one of the libraries involved (but in which of the three). Can the example be simplified even more to find it out?

0

There are 0 answers