nlohmann / json

JSON for Modern C++
https://json.nlohmann.me
MIT License
42.34k stars 6.67k forks source link

Compiler warning 'array-bounds' on g++12.2.0 on Ubuntu 22.10 kinetic with RelWithDebugInfo #3808

Open NeroBurner opened 1 year ago

NeroBurner commented 1 year ago

Description

On the latest Ubuntu 22.10 kinetic release -Werror in RelWithDebInfo can't be used because of compiler warning array-bounds

Reproduction steps

Build Release with Debug Info, enable warnings and error on them, then build test-constructor1_cpp11

cmake -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS="-Werror -Wall -Wextra -pedantic"
cmake --build build --target test-constructor1_cpp11

Get Build Error

Expected vs. actual results

expected: build without warning

actual result: build warning (leading to error because of my -Werror flag)

Minimal code example

// Unittest `constructor1.cpp` in `RelWithDebInfo` build type
TEST_CASE("constructors")
{
    SECTION("create a JSON container from an iterator range")
    {
        SECTION("other values")
        {
            SECTION("construct with two valid iterators")
            {
                SECTION("string")
                {
                    {
                        json j = "foo";
                        json const j_new(j.begin(), j.end());
                        CHECK(j == j_new);
                    }
                    {
                        json const j = "bar";
                        json const j_new(j.cbegin(), j.cend());
                        CHECK(j == j_new);
                    }
                }
            }
        }
    }
}

Error messages

cmake --build build --target test-constructor1_cpp11
[ 33%] Building CXX object tests/CMakeFiles/test_main.dir/src/unit.cpp.o
[ 33%] Built target test_main
[ 66%] Building CXX object tests/CMakeFiles/test-constructor1_cpp11.dir/src/unit-constructor1.cpp.o
In file included from /usr/include/c++/12/map:60,
                 from /home/nero/repos/external/nlohmann-json/include/nlohmann/detail/conversions/from_json.hpp:15,
                 from /home/nero/repos/external/nlohmann-json/include/nlohmann/adl_serializer.hpp:14,
                 from /home/nero/repos/external/nlohmann-json/include/nlohmann/json.hpp:35,
                 from /home/nero/repos/external/nlohmann-json/tests/src/unit-constructor1.cpp:12:
In member function 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::begin() [with _Key = std::__cxx11::basic_string<char>; _Val = std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> >; _KeyOfValue = std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > >; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > >]',
    inlined from 'std::map<_Key, _Tp, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::begin() [with _Key = std::__cxx11::basic_string<char>; _Tp = nlohmann::json_abi_v3_11_2::basic_json<>; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > >]' at /usr/include/c++/12/bits/stl_map.h:367:26,
    inlined from 'void nlohmann::json_abi_v3_11_2::detail::iter_impl<BasicJsonType>::set_begin() [with BasicJsonType = nlohmann::json_abi_v3_11_2::basic_json<>]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/detail/iterators/iter_impl.hpp:205:71,
    inlined from 'nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::iterator nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::begin() [with ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::json_abi_v3_11_2::adl_serializer; BinaryType = std::vector<unsigned char>]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/json.hpp:2761:25,
    inlined from 'void _DOCTEST_ANON_FUNC_2()' at /home/nero/repos/external/nlohmann-json/tests/src/unit-constructor1.cpp:1425:43:
/usr/include/c++/12/bits/stl_tree.h:996:16: error: array subscript 'std::_Rb_tree<std::__cxx11::basic_string<char>, std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> >, std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > >, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > > >[0]' is partly outside array bounds of 'unsigned char [32]' [-Werror=array-bounds]
  996 |       { return iterator(this->_M_impl._M_header._M_left); }
      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /usr/include/x86_64-linux-gnu/c++/12/bits/c++allocator.h:33,
                 from /usr/include/c++/12/bits/allocator.h:46,
                 from /usr/include/c++/12/string:41,
                 from /usr/include/c++/12/bits/locale_classes.h:40,
                 from /usr/include/c++/12/bits/ios_base.h:41,
                 from /usr/include/c++/12/streambuf:41,
                 from /usr/include/c++/12/bits/streambuf_iterator.h:35,
                 from /usr/include/c++/12/iterator:66,
                 from /home/nero/repos/external/nlohmann-json/include/nlohmann/json.hpp:28:
In member function '_Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::__cxx11::basic_string<char>]',
    inlined from 'static _Tp* std::allocator_traits<std::allocator<_CharT> >::allocate(allocator_type&, size_type) [with _Tp = std::__cxx11::basic_string<char>]' at /usr/include/c++/12/bits/alloc_traits.h:464:28,
    inlined from 'static T* nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::create(Args&& ...) [with T = std::__cxx11::basic_string<char>; Args = {const char (&)[4]}; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::json_abi_v3_11_2::adl_serializer; BinaryType = std::vector<unsigned char>]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/json.hpp:387:47,
    inlined from 'static void nlohmann::json_abi_v3_11_2::detail::external_constructor<nlohmann::json_abi_v3_11_2::detail::value_t::string>::construct(BasicJsonType&, const CompatibleStringType&) [with BasicJsonType = nlohmann::json_abi_v3_11_2::basic_json<>; CompatibleStringType = char [4]; typename std::enable_if<(! std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value), int>::type <anonymous> = 0]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp:85:79,
    inlined from 'void nlohmann::json_abi_v3_11_2::detail::to_json(BasicJsonType&, const CompatibleString&) [with BasicJsonType = nlohmann::json_abi_v3_11_2::basic_json<>; CompatibleString = char [4]; typename std::enable_if<std::is_constructible<typename BasicJsonType::string_t, Key>::value, int>::type <anonymous> = 0]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp:287:53,
    inlined from 'decltype ((nlohmann::json_abi_v3_11_2::detail::to_json(j, forward<T>(val)), void())) nlohmann::json_abi_v3_11_2::detail::to_json_fn::operator()(BasicJsonType&, T&&) const [with BasicJsonType = nlohmann::json_abi_v3_11_2::basic_json<>; T = const char (&)[4]]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp:428:23,
    inlined from 'static decltype ((nlohmann::json_abi_v3_11_2::{anonymous}::to_json(j, forward<TargetType>(val)), void())) nlohmann::json_abi_v3_11_2::adl_serializer<T, SFINAE>::to_json(BasicJsonType&, TargetType&&) [with BasicJsonType = nlohmann::json_abi_v3_11_2::basic_json<>; TargetType = const char (&)[4]; ValueType = char [4]; <template-parameter-1-2> = void]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/adl_serializer.hpp:51:28,
    inlined from 'nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::basic_json(CompatibleType&&) [with CompatibleType = const char (&)[4]; U = char [4]; typename std::enable_if<((! nlohmann::json_abi_v3_11_2::detail::is_basic_json<U>::value) && nlohmann::json_abi_v3_11_2::detail::is_compatible_type<nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>, U>::value), int>::type <anonymous> = 0; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::json_abi_v3_11_2::adl_serializer; BinaryType = std::vector<unsigned char>]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/json.hpp:829:35,
    inlined from 'void _DOCTEST_ANON_FUNC_2()' at /home/nero/repos/external/nlohmann-json/tests/src/unit-constructor1.cpp:1424:34:
/usr/include/c++/12/bits/new_allocator.h:137:55: note: object of size 32 allocated by 'operator new'
  137 |         return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
      |                                                       ^
In member function 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::begin() [with _Key = std::__cxx11::basic_string<char>; _Val = std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> >; _KeyOfValue = std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > >; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > >]',
    inlined from 'std::map<_Key, _Tp, _Compare, _Alloc>::iterator std::map<_Key, _Tp, _Compare, _Alloc>::begin() [with _Key = std::__cxx11::basic_string<char>; _Tp = nlohmann::json_abi_v3_11_2::basic_json<>; _Compare = std::less<std::__cxx11::basic_string<char> >; _Alloc = std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > >]' at /usr/include/c++/12/bits/stl_map.h:367:26,
    inlined from 'void nlohmann::json_abi_v3_11_2::detail::iter_impl<BasicJsonType>::set_begin() [with BasicJsonType = const nlohmann::json_abi_v3_11_2::basic_json<>]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/detail/iterators/iter_impl.hpp:205:71,
    inlined from 'nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::const_iterator nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::cbegin() const [with ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::json_abi_v3_11_2::adl_serializer; BinaryType = std::vector<unsigned char>]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/json.hpp:2777:25,
    inlined from 'void _DOCTEST_ANON_FUNC_2()' at /home/nero/repos/external/nlohmann-json/tests/src/unit-constructor1.cpp:1430:44:
/usr/include/c++/12/bits/stl_tree.h:996:16: error: array subscript 'std::_Rb_tree<std::__cxx11::basic_string<char>, std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> >, std::_Select1st<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > >, std::less<std::__cxx11::basic_string<char> >, std::allocator<std::pair<const std::__cxx11::basic_string<char>, nlohmann::json_abi_v3_11_2::basic_json<> > > >[0]' is partly outside array bounds of 'unsigned char [32]' [-Werror=array-bounds]
  996 |       { return iterator(this->_M_impl._M_header._M_left); }
      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In member function '_Tp* std::__new_allocator<_Tp>::allocate(size_type, const void*) [with _Tp = std::__cxx11::basic_string<char>]',
    inlined from 'static _Tp* std::allocator_traits<std::allocator<_CharT> >::allocate(allocator_type&, size_type) [with _Tp = std::__cxx11::basic_string<char>]' at /usr/include/c++/12/bits/alloc_traits.h:464:28,
    inlined from 'static T* nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::create(Args&& ...) [with T = std::__cxx11::basic_string<char>; Args = {const char (&)[4]}; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::json_abi_v3_11_2::adl_serializer; BinaryType = std::vector<unsigned char>]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/json.hpp:387:47,
    inlined from 'static void nlohmann::json_abi_v3_11_2::detail::external_constructor<nlohmann::json_abi_v3_11_2::detail::value_t::string>::construct(BasicJsonType&, const CompatibleStringType&) [with BasicJsonType = nlohmann::json_abi_v3_11_2::basic_json<>; CompatibleStringType = char [4]; typename std::enable_if<(! std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value), int>::type <anonymous> = 0]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp:85:79,
    inlined from 'void nlohmann::json_abi_v3_11_2::detail::to_json(BasicJsonType&, const CompatibleString&) [with BasicJsonType = nlohmann::json_abi_v3_11_2::basic_json<>; CompatibleString = char [4]; typename std::enable_if<std::is_constructible<typename BasicJsonType::string_t, Key>::value, int>::type <anonymous> = 0]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp:287:53,
    inlined from 'decltype ((nlohmann::json_abi_v3_11_2::detail::to_json(j, forward<T>(val)), void())) nlohmann::json_abi_v3_11_2::detail::to_json_fn::operator()(BasicJsonType&, T&&) const [with BasicJsonType = nlohmann::json_abi_v3_11_2::basic_json<>; T = const char (&)[4]]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/detail/conversions/to_json.hpp:428:23,
    inlined from 'static decltype ((nlohmann::json_abi_v3_11_2::{anonymous}::to_json(j, forward<TargetType>(val)), void())) nlohmann::json_abi_v3_11_2::adl_serializer<T, SFINAE>::to_json(BasicJsonType&, TargetType&&) [with BasicJsonType = nlohmann::json_abi_v3_11_2::basic_json<>; TargetType = const char (&)[4]; ValueType = char [4]; <template-parameter-1-2> = void]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/adl_serializer.hpp:51:28,
    inlined from 'nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>::basic_json(CompatibleType&&) [with CompatibleType = const char (&)[4]; U = char [4]; typename std::enable_if<((! nlohmann::json_abi_v3_11_2::detail::is_basic_json<U>::value) && nlohmann::json_abi_v3_11_2::detail::is_compatible_type<nlohmann::json_abi_v3_11_2::basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType>, U>::value), int>::type <anonymous> = 0; ObjectType = std::map; ArrayType = std::vector; StringType = std::__cxx11::basic_string<char>; BooleanType = bool; NumberIntegerType = long int; NumberUnsignedType = long unsigned int; NumberFloatType = double; AllocatorType = std::allocator; JSONSerializer = nlohmann::json_abi_v3_11_2::adl_serializer; BinaryType = std::vector<unsigned char>]' at /home/nero/repos/external/nlohmann-json/include/nlohmann/json.hpp:829:35,
    inlined from 'void _DOCTEST_ANON_FUNC_2()' at /home/nero/repos/external/nlohmann-json/tests/src/unit-constructor1.cpp:1429:34:
/usr/include/c++/12/bits/new_allocator.h:137:55: note: object of size 32 allocated by 'operator new'
  137 |         return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp)));
      |                                                       ^
cc1plus: all warnings being treated as errors
gmake[3]: *** [tests/CMakeFiles/test-constructor1_cpp11.dir/build.make:76: tests/CMakeFiles/test-constructor1_cpp11.dir/src/unit-constructor1.cpp.o] Error 1
gmake[2]: *** [CMakeFiles/Makefile2:1681: tests/CMakeFiles/test-constructor1_cpp11.dir/all] Error 2
gmake[1]: *** [CMakeFiles/Makefile2:1688: tests/CMakeFiles/test-constructor1_cpp11.dir/rule] Error 2
gmake: *** [Makefile:790: test-constructor1_cpp11] Error 2

Compiler and operating system

Ubuntu 22.10, g++12.2

Library version

3.11.2

Validation


edit: copied affected code from unit-constructor1.cpp to minimal example

NeroBurner commented 1 year ago

also happens on the g++12 compiler from Ubuntu 22.04 jammy

$ g++-12 --version
g++-12 (Ubuntu 12.1.0-2ubuntu1~22.04) 12.1.0
falbrechtskirchinger commented 1 year ago

I'd class this as a false positive. The compiler is complaining about the call to begin() here:

    void set_begin() noexcept
    {
        JSON_ASSERT(m_object != nullptr);

        switch (m_object->m_type)
        {
            case value_t::object:
            {
                m_it.object_iterator = m_object->m_value.object->begin();
                break;
            }

Of course, this call will only happen if the correct type (i.e. std::map) is stored. m_type is value_t::string in this case.

NeroBurner commented 11 months ago

still happens on Ubuntu 23.10 mantis with gcc (Ubuntu 13.2.0-4ubuntu3) 13.2.0

tested on current develop branch with commit edffad036d5a93ab5a10f72a7d835eeb0d2948f9

kkarbowiak commented 1 month ago

Still happens on Ubuntu 24.04 with g++ (Ubuntu 13.2.0-23ubuntu4) 13.2.0 and develop branch commit 960b763e.