From ae43e8ded4f787a06c6ecaf8a3dfc5fbce20a1b0 Mon Sep 17 00:00:00 2001 From: Michael Sam Date: Mon, 6 Jul 2026 13:39:03 +0300 Subject: [PATCH] Fix allocation failure during JSON destruction Signed-off-by: Michael Sam Signed-off-by: Niels Lohmann --- tests/src/unit-regression2.cpp | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/src/unit-regression2.cpp b/tests/src/unit-regression2.cpp index 79ca5a770..3548219f0 100644 --- a/tests/src/unit-regression2.cpp +++ b/tests/src/unit-regression2.cpp @@ -40,7 +40,9 @@ using ordered_json = nlohmann::ordered_json; #endif #include +#include #include +#include #include #include #include @@ -107,6 +109,49 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") using float_json = nlohmann::basic_json; +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) +namespace +{ +bool fail_next_global_allocation = false; + +void* checked_malloc(std::size_t size) +{ + if (fail_next_global_allocation) + { + fail_next_global_allocation = false; + throw std::bad_alloc(); + } + + if (void* const result = std::malloc(size)) + { + return result; + } + + throw std::bad_alloc(); +} +} // namespace + +void* operator new (std::size_t size) +{ + return checked_malloc(size); +} + +void* operator new[](std::size_t size) +{ + return checked_malloc(size); +} + +void operator delete (void* ptr) noexcept +{ + std::free(ptr); +} + +void operator delete[](void* ptr) noexcept +{ + std::free(ptr); +} +#endif + ///////////////////////////////////////////////////////////////////// // for #1647 ///////////////////////////////////////////////////////////////////// @@ -940,4 +985,19 @@ TEST_CASE("regression test - excessive binary container size honors allow_except CHECK(json::from_cbor(std::vector {0x9b, 0, 0, 0, 0, 0, 0, 0, 0x02}, true, false).is_discarded()); } +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) +TEST_CASE("regression test #5135 - destructor tolerates stack allocation failure") +{ + { + json j = json::array({json::array({1, 2}), json::object({{"key", json::array({3})}})}); + fail_next_global_allocation = true; + } + + const bool allocation_failure_was_injected = !fail_next_global_allocation; + fail_next_global_allocation = false; + + CHECK(allocation_failure_was_injected); +} +#endif + DOCTEST_CLANG_SUPPRESS_WARNING_POP