Merge branch 'claude/fix-allocation-exception-safety' into issue-5742-diagnostics-array-bounds
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
6 files changed
+305
-82
No files matched your search
@@ -42,6 +42,10 @@ namespace detail
|
||||
* j.m_data.m_value.destroy(j.m_data.m_type) to avoid a memory leak in case j contains an
|
||||
* allocated value (e.g., a string). See bug issue
|
||||
* https://github.com/nlohmann/json/issues/2865 for more information.
|
||||
*
|
||||
* A value that has to be allocated is created before the old one is destroyed:
|
||||
* were it the other way around, an exception while creating the new value would
|
||||
* leave j with the type of the new value, but the pointer to the destroyed old one.
|
||||
*/
|
||||
|
||||
template<value_t> struct external_constructor;
|
||||
@@ -65,18 +69,20 @@ struct external_constructor<value_t::string>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s)
|
||||
{
|
||||
const typename BasicJsonType::json_value value(s);
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::string;
|
||||
j.m_data.m_value = s;
|
||||
j.m_data.m_value = value;
|
||||
j.assert_invariant();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
||||
{
|
||||
const typename BasicJsonType::json_value value(std::move(s));
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::string;
|
||||
j.m_data.m_value = std::move(s);
|
||||
j.m_data.m_value = value;
|
||||
j.assert_invariant();
|
||||
}
|
||||
|
||||
@@ -85,9 +91,10 @@ struct external_constructor<value_t::string>
|
||||
int > = 0 >
|
||||
static void construct(BasicJsonType& j, const CompatibleStringType& str)
|
||||
{
|
||||
auto* created = j.template create<typename BasicJsonType::string_t>(str);
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::string;
|
||||
j.m_data.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
|
||||
j.m_data.m_value.string = created;
|
||||
j.assert_invariant();
|
||||
}
|
||||
};
|
||||
@@ -98,18 +105,20 @@ struct external_constructor<value_t::binary>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::binary_t& b)
|
||||
{
|
||||
const typename BasicJsonType::json_value value(b);
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::binary;
|
||||
j.m_data.m_value = typename BasicJsonType::binary_t(b);
|
||||
j.m_data.m_value = value;
|
||||
j.assert_invariant();
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::binary_t&& b)
|
||||
{
|
||||
const typename BasicJsonType::json_value value(std::move(b));
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::binary;
|
||||
j.m_data.m_value = typename BasicJsonType::binary_t(std::move(b));
|
||||
j.m_data.m_value = value;
|
||||
j.assert_invariant();
|
||||
}
|
||||
};
|
||||
@@ -159,9 +168,10 @@ struct external_constructor<value_t::array>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr)
|
||||
{
|
||||
const typename BasicJsonType::json_value value(arr);
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value = arr;
|
||||
j.m_data.m_value = value;
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
@@ -169,9 +179,10 @@ struct external_constructor<value_t::array>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||
{
|
||||
const typename BasicJsonType::json_value value(std::move(arr));
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value = std::move(arr);
|
||||
j.m_data.m_value = value;
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
@@ -187,9 +198,10 @@ struct external_constructor<value_t::array>
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
auto* created = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value.array = j.template create<typename BasicJsonType::array_t>(begin(arr), end(arr));
|
||||
j.m_data.m_value.array = created;
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
@@ -197,15 +209,17 @@ struct external_constructor<value_t::array>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const std::vector<bool>& arr)
|
||||
{
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value = value_t::array;
|
||||
j.m_data.m_value.array->reserve(arr.size());
|
||||
typename BasicJsonType::array_t elements;
|
||||
elements.reserve(arr.size());
|
||||
for (const bool x : arr)
|
||||
{
|
||||
j.m_data.m_value.array->push_back(x);
|
||||
j.set_parent(j.m_data.m_value.array->back());
|
||||
elements.push_back(x);
|
||||
}
|
||||
const typename BasicJsonType::json_value value(std::move(elements));
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value = value;
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
|
||||
@@ -213,11 +227,12 @@ struct external_constructor<value_t::array>
|
||||
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||
static void construct(BasicJsonType& j, const std::valarray<T>& arr)
|
||||
{
|
||||
typename BasicJsonType::array_t elements(arr.size());
|
||||
std::copy(std::begin(arr), std::end(arr), elements.begin());
|
||||
const typename BasicJsonType::json_value value(std::move(elements));
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value = value_t::array;
|
||||
j.m_data.m_value.array->resize(arr.size());
|
||||
std::copy(std::begin(arr), std::end(arr), j.m_data.m_value.array->begin());
|
||||
j.m_data.m_value = value;
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
@@ -229,14 +244,16 @@ struct external_constructor<value_t::array>
|
||||
enable_if_t<is_compatible_range_view<std::remove_cvref_t<CompatibleArrayType>>::value, int> = 0>
|
||||
static void construct(BasicJsonType& j, CompatibleArrayType && arr)
|
||||
{
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value = value_t::array;
|
||||
typename BasicJsonType::array_t elements;
|
||||
for (auto&& x : std::forward<CompatibleArrayType>(arr))
|
||||
{
|
||||
j.m_data.m_value.array->push_back(x);
|
||||
j.set_parent(j.m_data.m_value.array->back());
|
||||
elements.push_back(x);
|
||||
}
|
||||
const typename BasicJsonType::json_value value(std::move(elements));
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::array;
|
||||
j.m_data.m_value = value;
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
#endif
|
||||
@@ -248,9 +265,10 @@ struct external_constructor<value_t::object>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj)
|
||||
{
|
||||
const typename BasicJsonType::json_value value(obj);
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::object;
|
||||
j.m_data.m_value = obj;
|
||||
j.m_data.m_value = value;
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
@@ -258,9 +276,10 @@ struct external_constructor<value_t::object>
|
||||
template<typename BasicJsonType>
|
||||
static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||
{
|
||||
const typename BasicJsonType::json_value value(std::move(obj));
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::object;
|
||||
j.m_data.m_value = std::move(obj);
|
||||
j.m_data.m_value = value;
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
@@ -272,9 +291,10 @@ struct external_constructor<value_t::object>
|
||||
using std::begin;
|
||||
using std::end;
|
||||
|
||||
auto* created = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
|
||||
j.m_data.m_value.destroy(j.m_data.m_type);
|
||||
j.m_data.m_type = value_t::object;
|
||||
j.m_data.m_value.object = j.template create<typename BasicJsonType::object_t>(begin(obj), end(obj));
|
||||
j.m_data.m_value.object = created;
|
||||
j.set_parents();
|
||||
j.assert_invariant();
|
||||
}
|
||||
|
||||
+14
-14
@@ -1906,8 +1906,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
if (is_an_object)
|
||||
{
|
||||
// the initializer list is a list of pairs -> create an object
|
||||
m_data.m_type = value_t::object;
|
||||
m_data.m_value = value_t::object;
|
||||
m_data.m_type = value_t::object;
|
||||
|
||||
for (auto& element_ref : init)
|
||||
{
|
||||
@@ -1929,8 +1929,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
#endif
|
||||
// the initializer list describes an array -> create an array
|
||||
m_data.m_type = value_t::array;
|
||||
m_data.m_value.array = create<array_t>(init.begin(), init.end());
|
||||
m_data.m_type = value_t::array;
|
||||
}
|
||||
|
||||
set_parents();
|
||||
@@ -1943,8 +1943,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static basic_json binary(const typename binary_t::container_type& init)
|
||||
{
|
||||
auto res = basic_json();
|
||||
res.m_data.m_type = value_t::binary;
|
||||
res.m_data.m_value = init;
|
||||
res.m_data.m_type = value_t::binary;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1954,8 +1954,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static basic_json binary(const typename binary_t::container_type& init, typename binary_t::subtype_type subtype)
|
||||
{
|
||||
auto res = basic_json();
|
||||
res.m_data.m_type = value_t::binary;
|
||||
res.m_data.m_value = binary_t(init, subtype);
|
||||
res.m_data.m_type = value_t::binary;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1965,8 +1965,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static basic_json binary(typename binary_t::container_type&& init)
|
||||
{
|
||||
auto res = basic_json();
|
||||
res.m_data.m_type = value_t::binary;
|
||||
res.m_data.m_value = std::move(init);
|
||||
res.m_data.m_type = value_t::binary;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1976,8 +1976,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static basic_json binary(typename binary_t::container_type&& init, typename binary_t::subtype_type subtype)
|
||||
{
|
||||
auto res = basic_json();
|
||||
res.m_data.m_type = value_t::binary;
|
||||
res.m_data.m_value = binary_t(std::move(init), subtype);
|
||||
res.m_data.m_type = value_t::binary;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -3023,8 +3023,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// implicitly convert a null value to an empty array
|
||||
if (is_null())
|
||||
{
|
||||
m_data.m_type = value_t::array;
|
||||
m_data.m_value.array = create<array_t>();
|
||||
m_data.m_type = value_t::array;
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
@@ -3090,8 +3090,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// implicitly convert a null value to an empty object
|
||||
if (is_null())
|
||||
{
|
||||
m_data.m_type = value_t::object;
|
||||
m_data.m_value.object = create<object_t>();
|
||||
m_data.m_type = value_t::object;
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
@@ -3143,8 +3143,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// implicitly convert a null value to an empty object
|
||||
if (is_null())
|
||||
{
|
||||
m_data.m_type = value_t::object;
|
||||
m_data.m_value.object = create<object_t>();
|
||||
m_data.m_type = value_t::object;
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
@@ -4094,8 +4094,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// transform a null object into an array
|
||||
if (is_null())
|
||||
{
|
||||
m_data.m_type = value_t::array;
|
||||
m_data.m_value = value_t::array;
|
||||
m_data.m_type = value_t::array;
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
@@ -4127,8 +4127,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// transform a null object into an array
|
||||
if (is_null())
|
||||
{
|
||||
m_data.m_type = value_t::array;
|
||||
m_data.m_value = value_t::array;
|
||||
m_data.m_type = value_t::array;
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
@@ -4159,8 +4159,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// transform a null object into an object
|
||||
if (is_null())
|
||||
{
|
||||
m_data.m_type = value_t::object;
|
||||
m_data.m_value = value_t::object;
|
||||
m_data.m_type = value_t::object;
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
@@ -4215,8 +4215,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// transform a null object into an array
|
||||
if (is_null())
|
||||
{
|
||||
m_data.m_type = value_t::array;
|
||||
m_data.m_value = value_t::array;
|
||||
m_data.m_type = value_t::array;
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
@@ -4240,8 +4240,8 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
// transform a null object into an object
|
||||
if (is_null())
|
||||
{
|
||||
m_data.m_type = value_t::object;
|
||||
m_data.m_value = value_t::object;
|
||||
m_data.m_type = value_t::object;
|
||||
assert_invariant();
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user