From 6b8d2f3d9220bd8bcc304ae7c03c19608f9a9fcf Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Thu, 1 Oct 2026 07:51:39 +0200 Subject: [PATCH] Suppress GCC's false -Warray-bounds error in set_parents() with JSON_DIAGNOSTICS With JSON_DIAGNOSTICS, GCC 13 to 15 report a false -Warray-bounds error at -O3 when set_parents() is inlined right after a non-container value (e.g., a string) was created: the std::map access in the object branch is checked against the string allocation although m_type rules that branch out. GCC 15 fixed the pattern from #4819 but not this one. Suppress -Warray-bounds around set_parents() only, and add a regression test that is compiled with -O3 -Werror=array-bounds on GCC. Fixes #5742 Signed-off-by: Niels Lohmann --- include/nlohmann/json.hpp | 12 ++++ single_include/nlohmann/json.hpp | 12 ++++ tests/CMakeLists.txt | 5 ++ tests/src/unit-diagnostics-optimized.cpp | 76 ++++++++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 tests/src/unit-diagnostics-optimized.cpp diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 91efcf27c..f975657db 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -763,6 +763,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static_cast(check_parents); } + // GCC 13 to at least 15 report a false -Warray-bounds error when set_parents() + // is inlined at -O3 right after a non-container value was created: the analysis + // does not use m_type to rule out the object/array branches and checks + // the std::map access against the allocation of, e.g., a string. + // See https://github.com/nlohmann/json/issues/5742 and #4819. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif void set_parents() { #if JSON_DIAGNOSTICS @@ -799,6 +808,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } #endif } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif iterator set_parents(iterator it, std::ptrdiff_t count_set_parents) { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0e394cb10..849645b41 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -27441,6 +27441,15 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec static_cast(check_parents); } + // GCC 13 to at least 15 report a false -Warray-bounds error when set_parents() + // is inlined at -O3 right after a non-container value was created: the analysis + // does not use m_type to rule out the object/array branches and checks + // the std::map access against the allocation of, e.g., a string. + // See https://github.com/nlohmann/json/issues/5742 and #4819. +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif void set_parents() { #if JSON_DIAGNOSTICS @@ -27477,6 +27486,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec } #endif } +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#endif iterator set_parents(iterator it, std::ptrdiff_t count_set_parents) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ef1300ff6..16c135b8a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -139,6 +139,11 @@ json_test_set_test_options(test-unicode4 TEST_PROPERTIES TIMEOUT 3000) # only the #972 regression test needs thirdparty/fifo_map on its include path json_test_set_test_options(test-regression1 LINK_LIBRARIES fifo_map_include) +# GCC's false -Warray-bounds error with JSON_DIAGNOSTICS only shows up when optimizing (#5742) +json_test_set_test_options(test-diagnostics-optimized + COMPILE_OPTIONS $<$:-O3 -Werror=array-bounds> +) + ############################################################################# # add unit tests ############################################################################# diff --git a/tests/src/unit-diagnostics-optimized.cpp b/tests/src/unit-diagnostics-optimized.cpp new file mode 100644 index 000000000..0d715c325 --- /dev/null +++ b/tests/src/unit-diagnostics-optimized.cpp @@ -0,0 +1,76 @@ +// __ _____ _____ _____ +// __| | __| | | | JSON for Modern C++ (supporting code) +// | | |__ | | | | | | version 3.12.0 +// |_____|_____|_____|_|___| https://github.com/nlohmann/json +// +// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann +// SPDX-License-Identifier: MIT + +// Regression test for https://github.com/nlohmann/json/issues/5742: with +// JSON_DIAGNOSTICS, GCC (13 to at least 15) reports a false -Warray-bounds +// error in the inlined set_parents() at -O3. The warning depends on GCC's +// inlining decisions, so the sections cover patterns that trigger it on +// different GCC versions (#4819: GCC 13 and 14; #5742: GCC 14 and 15). +// On GCC, this file is compiled with -O3 -Werror=array-bounds (see +// tests/CMakeLists.txt), so the test fails to build if the warning returns. + +#include "doctest_compatibility.h" + +#ifdef JSON_DIAGNOSTICS + #undef JSON_DIAGNOSTICS +#endif + +#define JSON_DIAGNOSTICS 1 + +#include +using nlohmann::json; + +#include +#include +#include +#include + +namespace +{ +enum class diag_color +{ + red, + green, + blue +}; + +void to_json(json& j, const diag_color& c) +{ + static const std::pair m[] = // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + { + {diag_color::red, "r"}, + {diag_color::green, "g"}, + {diag_color::blue, "b"}, + }; + const auto* it = std::find_if(std::begin(m), std::end(m), [c](const std::pair& p) + { + return p.first == c; + }); + j = it->second; +} +} // namespace + +TEST_CASE("diagnostics with optimization") +{ + SECTION("issue #4819 - object in vector") + { + std::vector jsons{}; + jsons.emplace_back(json({{"key", "value"}})); + CHECK(jsons.back()["key"] == "value"); + } + + SECTION("issue #5742 - string values from a static table") + { + json j = json::array(); + j.push_back(diag_color::red); + j.push_back(diag_color::green); + j.push_back(diag_color::blue); + CHECK(j.dump() == R"(["r","g","b"])"); + CHECK_THROWS_WITH_AS(j[1].get(), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error); + } +}