mirror of
https://github.com/nlohmann/json.git
synced 2026-09-30 03:30:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
46b04c6024 |
@@ -37,22 +37,6 @@ Thereby, `Target` is the current object; that is, the patch is applied to the cu
|
||||
|
||||
Linear in the lengths of `apply_patch`.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! danger "Undefined behavior"
|
||||
|
||||
`merge_patch()` reads `apply_patch` while it modifies `#!cpp *this`. `apply_patch` must not be `#!cpp *this`
|
||||
itself and must not refer to a value contained in `#!cpp *this` (for example, a subobject returned by
|
||||
`#!cpp (*this)[key]`). Calling `merge_patch()` with such an argument reads the argument after it has been
|
||||
invalidated by the modification, which is undefined behavior. If the patch may alias `#!cpp *this`, pass a copy
|
||||
instead:
|
||||
|
||||
```cpp
|
||||
j.merge_patch(json(j)); // instead of j.merge_patch(j)
|
||||
```
|
||||
|
||||
See [GitHub issue #5641](https://github.com/nlohmann/json/issues/5641) for more information.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@@ -77,5 +61,3 @@ Linear in the lengths of `apply_patch`.
|
||||
## Version history
|
||||
|
||||
- Added in version 3.0.0.
|
||||
- Documented that `apply_patch` must not be `#!cpp *this` or refer to a value contained in `#!cpp *this`, in version
|
||||
3.13.0.
|
||||
|
||||
@@ -43,6 +43,9 @@ Strong guarantee: if an exception is thrown, there are no changes in the JSON va
|
||||
- Throws [`out_of_range.412`](../../home/exceptions.md#jsonexceptionout_of_range412) if the length of a document, array,
|
||||
string, or binary value exceeds the range of the 32-bit BSON length field; example:
|
||||
`"BSON length 2147483661 exceeds maximum of 2147483647"`
|
||||
- Throws [`out_of_range.415`](../../home/exceptions.md#jsonexceptionout_of_range415) if the subtype of a binary value
|
||||
exceeds 255, the maximum of the BSON binary subtype; example:
|
||||
`"subtype 70000 is too large for the BSON binary subtype (max 255)"`
|
||||
|
||||
## Complexity
|
||||
|
||||
@@ -78,3 +81,4 @@ pass before anything is written.
|
||||
|
||||
- Added in version 3.4.0.
|
||||
- Linear in the size of `j`, and no longer limited by the call stack for deeply nested values, since version 3.13.0.
|
||||
- `out_of_range.415` is now detected before anything is written, like the other exceptions above, since version 3.13.0.
|
||||
|
||||
@@ -59,22 +59,6 @@ Basic guarantee: if an exception is thrown during the operation, the JSON value
|
||||
1. O(N*log(size() + N)), where N is the number of elements to insert.
|
||||
2. O(N*log(size() + N)), where N is the number of elements to insert.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! danger "Undefined behavior"
|
||||
|
||||
Both overloads read the argument while they modify `#!cpp *this`. The argument `j` (or, for overload (2), the
|
||||
range `[first, last)`) must not be `#!cpp *this` itself and must not refer to a value contained in
|
||||
`#!cpp *this` (for example, a subobject returned by `#!cpp (*this)[key]`). Calling `update()` with such an
|
||||
argument reads the argument after it has been invalidated by the modification, which is undefined behavior. If
|
||||
the argument may alias `#!cpp *this`, pass a copy instead:
|
||||
|
||||
```cpp
|
||||
j.update(json(j["defaults"])); // instead of j.update(j["defaults"])
|
||||
```
|
||||
|
||||
See [GitHub issue #5641](https://github.com/nlohmann/json/issues/5641) for more information.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@@ -171,5 +155,3 @@ Basic guarantee: if an exception is thrown during the operation, the JSON value
|
||||
|
||||
- Added in version 3.0.0.
|
||||
- Added `merge_objects` parameter in 3.10.5.
|
||||
- Documented that the argument must not be `#!cpp *this` or refer to a value contained in `#!cpp *this`, in version
|
||||
3.13.0.
|
||||
|
||||
@@ -1055,15 +1055,26 @@ class binary_writer
|
||||
}
|
||||
|
||||
/*!
|
||||
@return The size of the BSON-encoded binary array @a value
|
||||
@return The size of the BSON-encoded binary array in @a j
|
||||
@throw out_of_range.415 if the subtype of @a j does not fit into a byte,
|
||||
before anything is written
|
||||
*/
|
||||
static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)
|
||||
static std::size_t calc_bson_binary_size(const BasicJsonType& j)
|
||||
{
|
||||
const auto& value = *j.m_data.m_value.binary;
|
||||
|
||||
if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j));
|
||||
}
|
||||
|
||||
return sizeof(std::int32_t) + value.size() + 1ul;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Writes a BSON element with key @a name and binary value @a value
|
||||
@pre @a value's subtype, if any, fits into a byte; @ref calc_bson_sizes
|
||||
checks this for every binary value in the document beforehand.
|
||||
*/
|
||||
void write_bson_binary(const string_t& name,
|
||||
const binary_t& value)
|
||||
@@ -1072,11 +1083,6 @@ class binary_writer
|
||||
|
||||
write_number<std::int32_t>(to_bson_length(value.size()), true);
|
||||
|
||||
if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), nullptr));
|
||||
}
|
||||
|
||||
write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00));
|
||||
|
||||
oa.write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
|
||||
@@ -1085,13 +1091,15 @@ class binary_writer
|
||||
/*!
|
||||
@return The size of the value of the BSON document entry for @a j, which
|
||||
is neither an object nor an array
|
||||
@throw out_of_range.415 if @a j is binary with a subtype that does not fit
|
||||
into a byte, before anything is written
|
||||
*/
|
||||
static std::size_t calc_bson_value_size(const BasicJsonType& j)
|
||||
{
|
||||
switch (j.type())
|
||||
{
|
||||
case value_t::binary:
|
||||
return calc_bson_binary_size(*j.m_data.m_value.binary);
|
||||
return calc_bson_binary_size(j);
|
||||
|
||||
case value_t::boolean:
|
||||
return 1ul;
|
||||
@@ -1217,6 +1225,8 @@ class binary_writer
|
||||
@return the size of @a document
|
||||
@throw out_of_range.409 if a key contains U+0000, before anything is
|
||||
written
|
||||
@throw out_of_range.415 if a binary value's subtype does not fit into a
|
||||
byte, before anything is written
|
||||
*/
|
||||
static std::size_t calc_bson_sizes(const BasicJsonType& document, std::vector<std::size_t>& nested_sizes)
|
||||
{
|
||||
|
||||
@@ -21385,15 +21385,26 @@ class binary_writer
|
||||
}
|
||||
|
||||
/*!
|
||||
@return The size of the BSON-encoded binary array @a value
|
||||
@return The size of the BSON-encoded binary array in @a j
|
||||
@throw out_of_range.415 if the subtype of @a j does not fit into a byte,
|
||||
before anything is written
|
||||
*/
|
||||
static std::size_t calc_bson_binary_size(const typename BasicJsonType::binary_t& value)
|
||||
static std::size_t calc_bson_binary_size(const BasicJsonType& j)
|
||||
{
|
||||
const auto& value = *j.m_data.m_value.binary;
|
||||
|
||||
if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), &j));
|
||||
}
|
||||
|
||||
return sizeof(std::int32_t) + value.size() + 1ul;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Writes a BSON element with key @a name and binary value @a value
|
||||
@pre @a value's subtype, if any, fits into a byte; @ref calc_bson_sizes
|
||||
checks this for every binary value in the document beforehand.
|
||||
*/
|
||||
void write_bson_binary(const string_t& name,
|
||||
const binary_t& value)
|
||||
@@ -21402,11 +21413,6 @@ class binary_writer
|
||||
|
||||
write_number<std::int32_t>(to_bson_length(value.size()), true);
|
||||
|
||||
if (value.has_subtype() && JSON_HEDLEY_UNLIKELY(value.subtype() > (std::numeric_limits<std::uint8_t>::max)()))
|
||||
{
|
||||
JSON_THROW(out_of_range::create(415, concat("subtype ", std::to_string(value.subtype()), " is too large for the BSON binary subtype (max 255)"), nullptr));
|
||||
}
|
||||
|
||||
write_number(value.has_subtype() ? static_cast<std::uint8_t>(value.subtype()) : static_cast<std::uint8_t>(0x00));
|
||||
|
||||
oa.write_characters(reinterpret_cast<const CharType*>(value.data()), value.size());
|
||||
@@ -21415,13 +21421,15 @@ class binary_writer
|
||||
/*!
|
||||
@return The size of the value of the BSON document entry for @a j, which
|
||||
is neither an object nor an array
|
||||
@throw out_of_range.415 if @a j is binary with a subtype that does not fit
|
||||
into a byte, before anything is written
|
||||
*/
|
||||
static std::size_t calc_bson_value_size(const BasicJsonType& j)
|
||||
{
|
||||
switch (j.type())
|
||||
{
|
||||
case value_t::binary:
|
||||
return calc_bson_binary_size(*j.m_data.m_value.binary);
|
||||
return calc_bson_binary_size(j);
|
||||
|
||||
case value_t::boolean:
|
||||
return 1ul;
|
||||
@@ -21547,6 +21555,8 @@ class binary_writer
|
||||
@return the size of @a document
|
||||
@throw out_of_range.409 if a key contains U+0000, before anything is
|
||||
written
|
||||
@throw out_of_range.415 if a binary value's subtype does not fit into a
|
||||
byte, before anything is written
|
||||
*/
|
||||
static std::size_t calc_bson_sizes(const BasicJsonType& document, std::vector<std::size_t>& nested_sizes)
|
||||
{
|
||||
|
||||
+20
-1
@@ -797,7 +797,11 @@ TEST_CASE("regression test - BSON binary subtype rejects a value that doesn't fi
|
||||
CHECK(json::from_bson(json::to_bson(doc255))["b"].get_binary().subtype() == 255);
|
||||
|
||||
CHECK_THROWS_AS(json::to_bson(json{{"b", json::binary({1, 2}, 256)}}), json::out_of_range);
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json{{"b", json::binary({1, 2}, 300)}}), "[json.exception.out_of_range.415] subtype 300 is too large for the BSON binary subtype (max 255)", json::out_of_range);
|
||||
#if JSON_DIAGNOSTICS
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"b", json::binary({1, 2}, 300)}}), "[json.exception.out_of_range.415] (/b) subtype 300 is too large for the BSON binary subtype (max 255)", json::out_of_range);
|
||||
#else
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(json {{"b", json::binary({1, 2}, 300)}}), "[json.exception.out_of_range.415] subtype 300 is too large for the BSON binary subtype (max 255)", json::out_of_range);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("BSON input/output_adapters")
|
||||
@@ -1805,6 +1809,21 @@ value = depth % 2 == 0 ? json{{"a", std::move(value)}, {"b", {1, "x"}}} :
|
||||
CHECK(output.empty());
|
||||
}
|
||||
|
||||
SECTION("a binary subtype that doesn't fit a byte is rejected before anything is written (#5675)")
|
||||
{
|
||||
// the offending value is nested, so this also covers that the check
|
||||
// is not limited to a directly written value's own document
|
||||
json const j = {{"a", {{"b", json::binary({1, 2}, 300)}}}};
|
||||
|
||||
std::vector<std::uint8_t> vector_output;
|
||||
CHECK_THROWS_AS(json::to_bson(j, vector_output), json::out_of_range&);
|
||||
CHECK(vector_output.empty());
|
||||
|
||||
std::string string_output;
|
||||
CHECK_THROWS_AS(json::to_bson(j, string_output), json::out_of_range&);
|
||||
CHECK(string_output.empty());
|
||||
}
|
||||
|
||||
SECTION("values nested too deeply for the call stack (#5392)")
|
||||
{
|
||||
// serializing recursed once per nesting level, and computed every
|
||||
|
||||
@@ -101,6 +101,12 @@ TEST_CASE("Regression tests for extended diagnostics")
|
||||
CHECK_THROWS_WITH_AS(j.unflatten(), "[json.exception.type_error.315] (/~1foo) values in object must be primitive", json::type_error);
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #5675 - to_bson: out_of_range.415 has no diagnostics context")
|
||||
{
|
||||
json const j = {{"a", {{"b", json::binary({1, 2}, 300)}}}};
|
||||
CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.out_of_range.415] (/a/b) subtype 300 is too large for the BSON binary subtype (max 255)", json::out_of_range);
|
||||
}
|
||||
|
||||
SECTION("Regression test for issue #2838 - Assertion failure when inserting into arrays with JSON_DIAGNOSTICS set")
|
||||
{
|
||||
// void push_back(basic_json&& val)
|
||||
|
||||
Reference in New Issue
Block a user