Prevent memory leak when exception is thrown in adl_serializer::to_json (#3901)

Co-authored-by: barcode <barcode@example.com>
This commit is contained in:
Raphael Grimm
2023-03-08 13:43:45 +01:00
committed by GitHub
parent fe4b66355c
commit bbe337c3a3
15 changed files with 1321 additions and 1167 deletions

View File

@@ -216,28 +216,28 @@ TEST_CASE("const_iterator class")
{
json const j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
it++;
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
}
SECTION("array")
{
json const j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
it++;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it++;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it++;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it++;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
}
}
@@ -267,28 +267,28 @@ TEST_CASE("const_iterator class")
{
json const j({{"foo", "bar"}});
json::const_iterator it = j.cbegin();
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
++it;
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
}
SECTION("array")
{
json const j({1, 2, 3, 4});
json::const_iterator it = j.cbegin();
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
++it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
++it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
++it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
++it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
}
}
@@ -316,28 +316,28 @@ TEST_CASE("const_iterator class")
{
json const j({{"foo", "bar"}});
json::const_iterator it = j.cend();
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
it--;
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
}
SECTION("array")
{
json const j({1, 2, 3, 4});
json::const_iterator it = j.cend();
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
it--;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it--;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it--;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it--;
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
}
}
@@ -365,28 +365,28 @@ TEST_CASE("const_iterator class")
{
json const j({{"foo", "bar"}});
json::const_iterator it = j.cend();
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
--it;
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
}
SECTION("array")
{
json const j({1, 2, 3, 4});
json::const_iterator it = j.cend();
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
--it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
--it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
--it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
--it;
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
}
}
}

View File

@@ -206,28 +206,28 @@ TEST_CASE("iterator class")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
it++;
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
it++;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it++;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it++;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it++;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
}
}
@@ -257,28 +257,28 @@ TEST_CASE("iterator class")
{
json j({{"foo", "bar"}});
json::iterator it = j.begin();
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
++it;
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.begin();
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
++it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
++it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
++it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
++it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
}
}
@@ -306,28 +306,28 @@ TEST_CASE("iterator class")
{
json j({{"foo", "bar"}});
json::iterator it = j.end();
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
it--;
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.end();
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
it--;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it--;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it--;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
it--;
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
}
}
@@ -355,28 +355,28 @@ TEST_CASE("iterator class")
{
json j({{"foo", "bar"}});
json::iterator it = j.end();
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->end()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->end()));
--it;
CHECK((it.m_it.object_iterator == it.m_object->m_value.object->begin()));
CHECK((it.m_it.object_iterator == it.m_object->m_data.m_value.object->begin()));
}
SECTION("array")
{
json j({1, 2, 3, 4});
json::iterator it = j.end();
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->end()));
--it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
--it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
--it;
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
--it;
CHECK((it.m_it.array_iterator == it.m_object->m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_value.array->end()));
CHECK((it.m_it.array_iterator == it.m_object->m_data.m_value.array->begin()));
CHECK((it.m_it.array_iterator != it.m_object->m_data.m_value.array->end()));
}
}
}

View File

@@ -872,7 +872,7 @@ TEST_CASE("constructors")
float const n = 42.23f;
json const j(n);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("double")
@@ -880,7 +880,7 @@ TEST_CASE("constructors")
double const n = 42.23;
json const j(n);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("long double")
@@ -888,28 +888,28 @@ TEST_CASE("constructors")
long double const n = 42.23L;
json const j(n);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("floating-point literal without suffix")
{
json const j(42.23);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("integer literal with f suffix")
{
json const j(42.23f);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
SECTION("integer literal with l suffix")
{
json const j(42.23L);
CHECK(j.type() == json::value_t::number_float);
CHECK(j.m_value.number_float == Approx(j_reference.m_value.number_float));
CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float));
}
}

View File

@@ -1076,19 +1076,19 @@ TEST_CASE("value conversion")
SECTION("number_float_t")
{
auto n = j.get<json::number_float_t>();
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
CHECK(json(n).m_data.m_value.number_float == Approx(j.m_data.m_value.number_float));
}
SECTION("float")
{
auto n = j.get<float>();
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
CHECK(json(n).m_data.m_value.number_float == Approx(j.m_data.m_value.number_float));
}
SECTION("double")
{
auto n = j.get<double>();
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
CHECK(json(n).m_data.m_value.number_float == Approx(j.m_data.m_value.number_float));
}
SECTION("exception in case of a non-string type")
@@ -1126,19 +1126,19 @@ TEST_CASE("value conversion")
SECTION("number_float_t")
{
json::number_float_t const n = j;
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
CHECK(json(n).m_data.m_value.number_float == Approx(j.m_data.m_value.number_float));
}
SECTION("float")
{
float const n = j;
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
CHECK(json(n).m_data.m_value.number_float == Approx(j.m_data.m_value.number_float));
}
SECTION("double")
{
double const n = j;
CHECK(json(n).m_value.number_float == Approx(j.m_value.number_float));
CHECK(json(n).m_data.m_value.number_float == Approx(j.m_data.m_value.number_float));
}
}
#endif
@@ -1151,7 +1151,7 @@ TEST_CASE("value conversion")
SECTION("binary_t")
{
json::binary_t const b = j.get<json::binary_t>();
CHECK(*json(b).m_value.binary == *j.m_value.binary);
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
}
SECTION("get_binary()")
@@ -1159,14 +1159,14 @@ TEST_CASE("value conversion")
SECTION("non-const")
{
auto& b = j.get_binary();
CHECK(*json(b).m_value.binary == *j.m_value.binary);
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
}
SECTION("non-const")
{
const json j_const = j;
const auto& b = j_const.get_binary();
CHECK(*json(b).m_value.binary == *j.m_value.binary);
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
}
}
@@ -1258,7 +1258,7 @@ TEST_CASE("value conversion")
SECTION("binary_t")
{
json::binary_t const b = j;
CHECK(*json(b).m_value.binary == *j.m_value.binary);
CHECK(*json(b).m_data.m_value.binary == *j.m_data.m_value.binary);
}
}
#endif

View File

@@ -0,0 +1,86 @@
// __ _____ _____ _____
// __| | __| | | | JSON for Modern C++ (supporting code)
// | | |__ | | | | | | version 3.11.2
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
//
// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT
#include "doctest_compatibility.h"
#include <nlohmann/json.hpp>
#include <exception>
#include <iostream>
struct Foo
{
int a;
int b;
};
namespace nlohmann
{
template <>
struct adl_serializer<Foo>
{
static void to_json(json& j, Foo const& f)
{
switch (f.b)
{
case 0:
j["a"] = f.a;
break;
case 1:
j[0] = f.a;
break;
default:
j = "test";
}
if (f.a == 1)
{
throw std::runtime_error("b is invalid");
}
}
};
} // namespace nlohmann
TEST_CASE("check_for_mem_leak_on_adl_to_json-1")
{
try
{
const nlohmann::json j = Foo {1, 0};
std::cout << j.dump() << "\n";
}
catch (...)
{
// just ignore the exception in this POC
}
}
TEST_CASE("check_for_mem_leak_on_adl_to_json-2")
{
try
{
const nlohmann::json j = Foo {1, 1};
std::cout << j.dump() << "\n";
}
catch (...)
{
// just ignore the exception in this POC
}
}
TEST_CASE("check_for_mem_leak_on_adl_to_json-2")
{
try
{
const nlohmann::json j = Foo {1, 2};
std::cout << j.dump() << "\n";
}
catch (...)
{
// just ignore the exception in this POC
}
}