Fix allocation failure during JSON destruction

Signed-off-by: Michael Sam <michaelsam94@users.noreply.github.com>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
Michael Sam
2026-10-04 18:11:25 +02:00
committed by Niels Lohmann
parent 5185181552
commit ae43e8ded4
+60
View File
@@ -40,7 +40,9 @@ using ordered_json = nlohmann::ordered_json;
#endif
#include <cstdio>
#include <cstdlib>
#include <list>
#include <new>
#include <tuple>
#include <type_traits>
#include <utility>
@@ -107,6 +109,49 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors")
using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
#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<std::uint8_t> {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