mirror of
https://github.com/nlohmann/json.git
synced 2026-11-03 11:25:33 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b12b92b30c | ||
|
|
414b4e6d27 | ||
|
|
da6d21ae24 | ||
|
|
db73a6044f |
No files matched your search
@@ -1024,7 +1024,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
std::uint64_t len{};
|
std::uint64_t len{};
|
||||||
std::size_t size{};
|
std::size_t size{};
|
||||||
return get_cbor_argument(len) && get_cbor_container_size(len, size, "array") && enter_cbor_array(size);
|
return get_cbor_argument(len) && get_container_size(len, size, "array") && enter_cbor_array(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x9F: // array (indefinite length)
|
case 0x9F: // array (indefinite length)
|
||||||
@@ -1064,7 +1064,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
std::uint64_t len{};
|
std::uint64_t len{};
|
||||||
std::size_t size{};
|
std::size_t size{};
|
||||||
return get_cbor_argument(len) && get_cbor_container_size(len, size, "map") && enter_object(size);
|
return get_cbor_argument(len) && get_container_size(len, size, "map") && enter_object(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xBF: // map (indefinite length)
|
case 0xBF: // map (indefinite length)
|
||||||
@@ -1700,7 +1700,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief narrow a definite CBOR array/map length to std::size_t
|
@brief narrow a definite CBOR or MessagePack array/map length to std::size_t
|
||||||
|
|
||||||
A definite length is rejected if it does not fit in std::size_t or if it
|
A definite length is rejected if it does not fit in std::size_t or if it
|
||||||
equals detail::unknown_size(), which is reserved to mark an indefinite-
|
equals detail::unknown_size(), which is reserved to mark an indefinite-
|
||||||
@@ -1713,7 +1713,7 @@ class binary_reader
|
|||||||
@param[in] context "array" or "map", for the error message
|
@param[in] context "array" or "map", for the error message
|
||||||
@return whether the length is usable
|
@return whether the length is usable
|
||||||
*/
|
*/
|
||||||
bool get_cbor_container_size(const std::uint64_t len, std::size_t& result, const char* context)
|
bool get_container_size(const std::uint64_t len, std::size_t& result, const char* context)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(len) || len == detail::unknown_size()))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(len) || len == detail::unknown_size()))
|
||||||
{
|
{
|
||||||
@@ -2309,7 +2309,8 @@ class binary_reader
|
|||||||
case 0xDD: // array 32
|
case 0xDD: // array 32
|
||||||
{
|
{
|
||||||
std::uint32_t len{};
|
std::uint32_t len{};
|
||||||
return get_number(len) && enter_msgpack_array(conditional_static_cast<std::size_t>(len));
|
std::size_t size{};
|
||||||
|
return get_number(len) && get_container_size(len, size, "array") && enter_msgpack_array(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xDE: // map 16
|
case 0xDE: // map 16
|
||||||
@@ -2321,7 +2322,8 @@ class binary_reader
|
|||||||
case 0xDF: // map 32
|
case 0xDF: // map 32
|
||||||
{
|
{
|
||||||
std::uint32_t len{};
|
std::uint32_t len{};
|
||||||
return get_number(len) && enter_object(conditional_static_cast<std::size_t>(len));
|
std::size_t size{};
|
||||||
|
return get_number(len) && get_container_size(len, size, "map") && enter_object(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// negative fixint
|
// negative fixint
|
||||||
@@ -3131,6 +3133,27 @@ class binary_reader
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief store the count of an optimized container (or the length of a string)
|
||||||
|
|
||||||
|
A count equal to npos is rejected: npos marks a container whose count is
|
||||||
|
not known, so a count of that value would be read as "no count" (compare
|
||||||
|
get_container_size()). No container can hold that many elements.
|
||||||
|
|
||||||
|
@param[in] count the count read from the input
|
||||||
|
@param[out] result set to @a count unless it is rejected
|
||||||
|
@return whether @a count is usable
|
||||||
|
*/
|
||||||
|
bool store_ubjson_count(const std::size_t count, std::size_t& result)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(count == npos))
|
||||||
|
{
|
||||||
|
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
||||||
|
}
|
||||||
|
result = count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief read a UBJSON/BJData optimized-container count of a signed marker
|
@brief read a UBJSON/BJData optimized-container count of a signed marker
|
||||||
type ('i', 'I', 'l', 'L') and narrow it to std::size_t
|
type ('i', 'I', 'l', 'L') and narrow it to std::size_t
|
||||||
@@ -3161,8 +3184,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
||||||
}
|
}
|
||||||
result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
return store_ubjson_count(static_cast<std::size_t>(number), result); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -3239,8 +3261,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
result = conditional_static_cast<std::size_t>(number);
|
return store_ubjson_count(conditional_static_cast<std::size_t>(number), result);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'M':
|
case 'M':
|
||||||
@@ -3258,8 +3279,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
||||||
}
|
}
|
||||||
result = detail::conditional_static_cast<std::size_t>(number);
|
return store_ubjson_count(detail::conditional_static_cast<std::size_t>(number), result);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case '[':
|
case '[':
|
||||||
|
|||||||
Generated
+32
-12
@@ -19039,7 +19039,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
std::uint64_t len{};
|
std::uint64_t len{};
|
||||||
std::size_t size{};
|
std::size_t size{};
|
||||||
return get_cbor_argument(len) && get_cbor_container_size(len, size, "array") && enter_cbor_array(size);
|
return get_cbor_argument(len) && get_container_size(len, size, "array") && enter_cbor_array(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x9F: // array (indefinite length)
|
case 0x9F: // array (indefinite length)
|
||||||
@@ -19079,7 +19079,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
std::uint64_t len{};
|
std::uint64_t len{};
|
||||||
std::size_t size{};
|
std::size_t size{};
|
||||||
return get_cbor_argument(len) && get_cbor_container_size(len, size, "map") && enter_object(size);
|
return get_cbor_argument(len) && get_container_size(len, size, "map") && enter_object(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xBF: // map (indefinite length)
|
case 0xBF: // map (indefinite length)
|
||||||
@@ -19715,7 +19715,7 @@ class binary_reader
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief narrow a definite CBOR array/map length to std::size_t
|
@brief narrow a definite CBOR or MessagePack array/map length to std::size_t
|
||||||
|
|
||||||
A definite length is rejected if it does not fit in std::size_t or if it
|
A definite length is rejected if it does not fit in std::size_t or if it
|
||||||
equals detail::unknown_size(), which is reserved to mark an indefinite-
|
equals detail::unknown_size(), which is reserved to mark an indefinite-
|
||||||
@@ -19728,7 +19728,7 @@ class binary_reader
|
|||||||
@param[in] context "array" or "map", for the error message
|
@param[in] context "array" or "map", for the error message
|
||||||
@return whether the length is usable
|
@return whether the length is usable
|
||||||
*/
|
*/
|
||||||
bool get_cbor_container_size(const std::uint64_t len, std::size_t& result, const char* context)
|
bool get_container_size(const std::uint64_t len, std::size_t& result, const char* context)
|
||||||
{
|
{
|
||||||
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(len) || len == detail::unknown_size()))
|
if (JSON_HEDLEY_UNLIKELY(!value_in_range_of<std::size_t>(len) || len == detail::unknown_size()))
|
||||||
{
|
{
|
||||||
@@ -20324,7 +20324,8 @@ class binary_reader
|
|||||||
case 0xDD: // array 32
|
case 0xDD: // array 32
|
||||||
{
|
{
|
||||||
std::uint32_t len{};
|
std::uint32_t len{};
|
||||||
return get_number(len) && enter_msgpack_array(conditional_static_cast<std::size_t>(len));
|
std::size_t size{};
|
||||||
|
return get_number(len) && get_container_size(len, size, "array") && enter_msgpack_array(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0xDE: // map 16
|
case 0xDE: // map 16
|
||||||
@@ -20336,7 +20337,8 @@ class binary_reader
|
|||||||
case 0xDF: // map 32
|
case 0xDF: // map 32
|
||||||
{
|
{
|
||||||
std::uint32_t len{};
|
std::uint32_t len{};
|
||||||
return get_number(len) && enter_object(conditional_static_cast<std::size_t>(len));
|
std::size_t size{};
|
||||||
|
return get_number(len) && get_container_size(len, size, "map") && enter_object(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// negative fixint
|
// negative fixint
|
||||||
@@ -21146,6 +21148,27 @@ class binary_reader
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief store the count of an optimized container (or the length of a string)
|
||||||
|
|
||||||
|
A count equal to npos is rejected: npos marks a container whose count is
|
||||||
|
not known, so a count of that value would be read as "no count" (compare
|
||||||
|
get_container_size()). No container can hold that many elements.
|
||||||
|
|
||||||
|
@param[in] count the count read from the input
|
||||||
|
@param[out] result set to @a count unless it is rejected
|
||||||
|
@return whether @a count is usable
|
||||||
|
*/
|
||||||
|
bool store_ubjson_count(const std::size_t count, std::size_t& result)
|
||||||
|
{
|
||||||
|
if (JSON_HEDLEY_UNLIKELY(count == npos))
|
||||||
|
{
|
||||||
|
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
||||||
|
}
|
||||||
|
result = count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief read a UBJSON/BJData optimized-container count of a signed marker
|
@brief read a UBJSON/BJData optimized-container count of a signed marker
|
||||||
type ('i', 'I', 'l', 'L') and narrow it to std::size_t
|
type ('i', 'I', 'l', 'L') and narrow it to std::size_t
|
||||||
@@ -21176,8 +21199,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
||||||
}
|
}
|
||||||
result = static_cast<std::size_t>(number); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
return store_ubjson_count(static_cast<std::size_t>(number), result); // NOLINT(bugprone-signed-char-misuse,cert-str34-c): number is not a char
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -21254,8 +21276,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
result = conditional_static_cast<std::size_t>(number);
|
return store_ubjson_count(conditional_static_cast<std::size_t>(number), result);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'M':
|
case 'M':
|
||||||
@@ -21273,8 +21294,7 @@ class binary_reader
|
|||||||
{
|
{
|
||||||
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
return out_of_range_error(exception_id::container_too_large, "integer value overflow", "size");
|
||||||
}
|
}
|
||||||
result = detail::conditional_static_cast<std::size_t>(number);
|
return store_ubjson_count(detail::conditional_static_cast<std::size_t>(number), result);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case '[':
|
case '[':
|
||||||
|
|||||||
@@ -97,3 +97,23 @@ TEST_CASE("CBOR")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("MessagePack")
|
||||||
|
{
|
||||||
|
SECTION("parse errors")
|
||||||
|
{
|
||||||
|
SECTION("array/map size equal to the unknown-size sentinel")
|
||||||
|
{
|
||||||
|
// on 32-bit platforms an array 32/map 32 length of 0xFFFFFFFF aliases unknown_size()
|
||||||
|
std::vector<uint8_t> const varr = {0xDD, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
std::vector<uint8_t> const vmap = {0xDF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
|
||||||
|
json _;
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_msgpack(varr), "[json.exception.out_of_range.408] syntax error while parsing MessagePack size: excessive array size", json::out_of_range&);
|
||||||
|
CHECK(json::from_msgpack(varr, true, false).is_discarded());
|
||||||
|
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_msgpack(vmap), "[json.exception.out_of_range.408] syntax error while parsing MessagePack size: excessive map size", json::out_of_range&);
|
||||||
|
CHECK(json::from_msgpack(vmap, true, false).is_discarded());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1038,14 +1038,6 @@ template<class T>
|
|||||||
struct sweep_allocator
|
struct sweep_allocator
|
||||||
{
|
{
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
// GCC 4.8's std::map takes these from the allocator instead of from
|
|
||||||
// std::allocator_traits
|
|
||||||
using pointer = T*;
|
|
||||||
using const_pointer = const T*;
|
|
||||||
using reference = T&;
|
|
||||||
using const_reference = const T&;
|
|
||||||
using size_type = std::size_t;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
|
|
||||||
sweep_allocator() = default;
|
sweep_allocator() = default;
|
||||||
template<class U> sweep_allocator(const sweep_allocator<U>& /*unused*/) noexcept {}
|
template<class U> sweep_allocator(const sweep_allocator<U>& /*unused*/) noexcept {}
|
||||||
@@ -1163,14 +1155,9 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)")
|
|||||||
|
|
||||||
// With iterator debugging (MSVC STL debug builds, also used by clang-cl),
|
// With iterator debugging (MSVC STL debug builds, also used by clang-cl),
|
||||||
// containers allocate a debug proxy through the allocator inside their
|
// containers allocate a debug proxy through the allocator inside their
|
||||||
// noexcept default and move constructors, so failing that allocation
|
// noexcept move constructors, so failing that allocation terminates the
|
||||||
// terminates the program instead of throwing std::bad_alloc. Nothing to
|
// program instead of throwing std::bad_alloc. Nothing to check there.
|
||||||
// check there.
|
|
||||||
#if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
|
#if !(defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0)
|
||||||
// Clang 3.4 and 3.5 leak memory when an element constructor throws
|
|
||||||
// inside libstdc++'s containers (a std::map copy, a std::vector
|
|
||||||
// reallocation), without any json value involved.
|
|
||||||
#if !(defined(__clang__) && !defined(__apple_build_version__) && __clang_major__ == 3 && __clang_minor__ < 6)
|
|
||||||
SECTION("parser callback")
|
SECTION("parser callback")
|
||||||
{
|
{
|
||||||
const auto keep_all = [](int /*depth*/, sweep_json::parse_event_t /*event*/, sweep_json& /*parsed*/) noexcept
|
const auto keep_all = [](int /*depth*/, sweep_json::parse_event_t /*event*/, sweep_json& /*parsed*/) noexcept
|
||||||
@@ -1191,6 +1178,7 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)")
|
|||||||
return sweep_json::parse(text, drop_d);
|
return sweep_json::parse(text, drop_d);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SECTION("sax_parse into an existing value")
|
SECTION("sax_parse into an existing value")
|
||||||
{
|
{
|
||||||
@@ -1204,7 +1192,5 @@ TEST_CASE("parse() survives a failing allocation at every point (#5985)")
|
|||||||
return value;
|
return value;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -3237,14 +3237,34 @@ TEST_CASE("BJData")
|
|||||||
#endif
|
#endif
|
||||||
CHECK(json::from_bjdata(vM, true, false).is_discarded());
|
CHECK(json::from_bjdata(vM, true, false).is_discarded());
|
||||||
|
|
||||||
#if SIZE_MAX != 0xffffffff
|
// the first dimension is 2^64-1, which is rejected as a count (see below)
|
||||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vMX), "[json.exception.out_of_range.408] syntax error while parsing BJData size: excessive ndarray size caused overflow", json::out_of_range&);
|
|
||||||
#else
|
|
||||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vMX), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
|
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vMX), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
|
||||||
#endif
|
|
||||||
CHECK(json::from_bjdata(vMX, true, false).is_discarded());
|
CHECK(json::from_bjdata(vMX, true, false).is_discarded());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("optimized array: count equal to SIZE_MAX")
|
||||||
|
{
|
||||||
|
// the reader marks a container without a count by SIZE_MAX, so
|
||||||
|
// a count of that value must not be read as "no count"
|
||||||
|
// (it used to parse as [1])
|
||||||
|
json _;
|
||||||
|
#if SIZE_MAX != 0xffffffff
|
||||||
|
std::vector<uint8_t> const vM = {'[', '#', 'M', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 'i', 0x01, ']'};
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
|
||||||
|
CHECK(json::from_bjdata(vM, true, false).is_discarded());
|
||||||
|
// one less is an ordinary excessive count
|
||||||
|
std::vector<uint8_t> const vM1 = {'[', '#', 'M', 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 'i', 0x01, ']'};
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vM1), "[json.exception.out_of_range.408] excessive array size: 18446744073709551614", json::out_of_range&);
|
||||||
|
#else
|
||||||
|
std::vector<uint8_t> const vm = {'[', '#', 'm', 0xFF, 0xFF, 0xFF, 0xFF, 'i', 0x01, ']'};
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vm), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
|
||||||
|
CHECK(json::from_bjdata(vm, true, false).is_discarded());
|
||||||
|
std::vector<uint8_t> const vL = {'[', '#', 'L', 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 'i', 0x01, ']'};
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vL), "[json.exception.out_of_range.408] syntax error while parsing BJData size: integer value overflow", json::out_of_range&);
|
||||||
|
CHECK(json::from_bjdata(vL, true, false).is_discarded());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("optimized array: integer value overflow")
|
SECTION("optimized array: integer value overflow")
|
||||||
{
|
{
|
||||||
#if SIZE_MAX == 0xffffffff
|
#if SIZE_MAX == 0xffffffff
|
||||||
|
|||||||
@@ -2222,10 +2222,9 @@ TEST_CASE("serialization of short strings")
|
|||||||
{
|
{
|
||||||
CAPTURE(s)
|
CAPTURE(s)
|
||||||
const json j = s;
|
const json j = s;
|
||||||
const std::string quoted = "\"" + s + "\""; // NOLINT(performance-inefficient-string-concatenation)
|
CHECK(j.dump() == "\"" + s + "\"");
|
||||||
CHECK(j.dump() == quoted);
|
CHECK(j.dump(-1, ' ', true) == "\"" + s + "\"");
|
||||||
CHECK(j.dump(-1, ' ', true) == quoted);
|
CHECK(json({{s, s}}).dump() == "{\"" + s + "\":\"" + s + "\"}");
|
||||||
CHECK(json({{s, s}}).dump() == "{" + quoted + ":" + quoted + "}"); // NOLINT(performance-inefficient-string-concatenation)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// a character that needs an escape
|
// a character that needs an escape
|
||||||
|
|||||||
@@ -160,12 +160,12 @@ class strict_key
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string m_value;
|
std::string m_value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
strict_key make_strict_key(const std::string& key)
|
strict_key make_strict_key(const std::string& key)
|
||||||
{
|
{
|
||||||
return {key.c_str()};
|
return strict_key(key.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Key, class Value, class Compare, class Allocator>
|
template<class Key, class Value, class Compare, class Allocator>
|
||||||
@@ -224,9 +224,7 @@ TEST_CASE("converting a value with keys that cannot be made from a std::string n
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// direct-initialization: a copy-initialization makes GCC 4.8 instantiate the
|
const strict_json converted = value;
|
||||||
// copy constructor, which needs a range constructor strict_object lacks
|
|
||||||
const strict_json converted(value);
|
|
||||||
|
|
||||||
// at() needs to make a std::string of a key for its error message
|
// at() needs to make a std::string of a key for its error message
|
||||||
const auto member = [](const strict_json & object, const char* name) -> const strict_json &
|
const auto member = [](const strict_json & object, const char* name) -> const strict_json &
|
||||||
|
|||||||
@@ -105,53 +105,19 @@ template<typename T>
|
|||||||
struct failing_allocator
|
struct failing_allocator
|
||||||
{
|
{
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
// GCC 4.8's std::map takes these from the allocator instead of from
|
|
||||||
// std::allocator_traits
|
|
||||||
using pointer = T*;
|
|
||||||
using const_pointer = const T*;
|
|
||||||
using reference = T&;
|
|
||||||
using const_reference = const T&;
|
|
||||||
using size_type = std::size_t;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
struct rebind
|
|
||||||
{
|
|
||||||
using other = failing_allocator<U>;
|
|
||||||
};
|
|
||||||
|
|
||||||
failing_allocator() = default;
|
failing_allocator() = default;
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
explicit failing_allocator(const failing_allocator<U>& /*other*/) noexcept {}
|
explicit failing_allocator(const failing_allocator<U>& /*other*/) noexcept {}
|
||||||
|
|
||||||
[[noreturn]] T* allocate(std::size_t /*n*/) // NOLINT(readability-convert-member-functions-to-static)
|
T* allocate(std::size_t /*n*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||||
{
|
{
|
||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
}
|
}
|
||||||
|
|
||||||
void deallocate(T* /*p*/, std::size_t /*n*/) noexcept {} // NOLINT(readability-convert-member-functions-to-static)
|
void deallocate(T* /*p*/, std::size_t /*n*/) noexcept {} // NOLINT(readability-convert-member-functions-to-static)
|
||||||
|
|
||||||
// GCC 4.8's std::map calls these on the allocator directly instead of
|
|
||||||
// going through std::allocator_traits
|
|
||||||
std::size_t max_size() const noexcept // NOLINT(readability-convert-member-functions-to-static)
|
|
||||||
{
|
|
||||||
return (std::numeric_limits<std::size_t>::max)() / sizeof(T);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, typename... Args>
|
|
||||||
void construct(U* p, Args&& ... args) // NOLINT(readability-convert-member-functions-to-static)
|
|
||||||
{
|
|
||||||
::new (static_cast<void*>(p)) U(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
void destroy(U* p) noexcept // NOLINT(readability-convert-member-functions-to-static)
|
|
||||||
{
|
|
||||||
static_cast<void>(p); // unused for trivially destructible types
|
|
||||||
p->~U();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
bool operator==(const failing_allocator<U>& /*other*/) const noexcept
|
bool operator==(const failing_allocator<U>& /*other*/) const noexcept
|
||||||
{
|
{
|
||||||
@@ -304,7 +270,7 @@ TEST_CASE("json_view")
|
|||||||
"\"", "\"abc", "\"\\x\"", "\"\\u12\"", "\"\\ud800\"", "\"\\udc00\"", "\"\x01\"", "\"\xff\"", "\"\xc3\"", "[1]x", "/", "/*", "[\n 1,\n x\n]", // NOLINT(modernize-raw-string-literal)
|
"\"", "\"abc", "\"\\x\"", "\"\\u12\"", "\"\\ud800\"", "\"\\udc00\"", "\"\x01\"", "\"\xff\"", "\"\xc3\"", "[1]x", "/", "/*", "[\n 1,\n x\n]", // NOLINT(modernize-raw-string-literal)
|
||||||
"1e400", "-1e400", "[1.7976931348623159e308]", "{\"a\":\n{\"b\": [1, 2,\n 3 x]}}",
|
"1e400", "-1e400", "[1.7976931348623159e308]", "{\"a\":\n{\"b\": [1, 2,\n 3 x]}}",
|
||||||
// (an error after every kind of value: the error is found by replaying the parser)
|
// (an error after every kind of value: the error is found by replaying the parser)
|
||||||
R"([null, true, -1, 1, 1.5, "s", {"a": 1} 2])", R"({"a": null, "b": -1, "c": 1.5, "d": "s", "e": {}, 1})"
|
"[null, true, -1, 1, 1.5, \"s\", {\"a\": 1} 2]", "{\"a\": null, \"b\": -1, \"c\": 1.5, \"d\": \"s\", \"e\": {}, 1}"
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
CAPTURE(text)
|
CAPTURE(text)
|
||||||
@@ -1590,7 +1556,7 @@ TEST_CASE("json_view values")
|
|||||||
CHECK_THROWS_WITH_AS(not_an_object.root().get<view_map>(), json_view_test::message("type_error.302", "", 0, 5, "type must be object, but is array").c_str(), json::type_error&);
|
CHECK_THROWS_WITH_AS(not_an_object.root().get<view_map>(), json_view_test::message("type_error.302", "", 0, 5, "type must be object, but is array").c_str(), json::type_error&);
|
||||||
#if !defined(JSON_NOEXCEPTION)
|
#if !defined(JSON_NOEXCEPTION)
|
||||||
// (and one that cannot allocate its nodes)
|
// (and one that cannot allocate its nodes)
|
||||||
using failing_map = std::map<std::string, json_view, std::less<std::string>, failing_allocator<std::pair<const std::string, json_view>>>; // NOLINT(modernize-use-transparent-functors)
|
using failing_map = std::map<std::string, json_view, std::less<std::string>, failing_allocator<std::pair<const std::string, json_view>>>;
|
||||||
const json_document one_member = json_document::parse(R"({"a":1})");
|
const json_document one_member = json_document::parse(R"({"a":1})");
|
||||||
CHECK_THROWS_AS(one_member.root().get<failing_map>(), std::bad_alloc&);
|
CHECK_THROWS_AS(one_member.root().get<failing_map>(), std::bad_alloc&);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -525,7 +525,7 @@ struct locale_switching_token
|
|||||||
{
|
{
|
||||||
switched = std::setlocale(LC_NUMERIC, switch_to.c_str()) != nullptr;
|
switched = std::setlocale(LC_NUMERIC, switch_to.c_str()) != nullptr;
|
||||||
}
|
}
|
||||||
return &text[0]; // NOLINT(readability-container-data-pointer): std::string::data() is const before C++17
|
return &text[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string text;
|
std::string text;
|
||||||
@@ -647,7 +647,7 @@ TEST_CASE("convert_float_locale_aware")
|
|||||||
|
|
||||||
// "C" -> comma locale: strtod stops at the '.', so the conversion is repeated
|
// "C" -> comma locale: strtod stops at the '.', so the conversion is repeated
|
||||||
{
|
{
|
||||||
locale_switching_token token("1.5", comma_locale);
|
locale_switching_token token("1.5", comma_locale.c_str());
|
||||||
double value = 0;
|
double value = 0;
|
||||||
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
||||||
if (token.switched)
|
if (token.switched)
|
||||||
@@ -660,7 +660,7 @@ TEST_CASE("convert_float_locale_aware")
|
|||||||
// the same for the other floating-point types
|
// the same for the other floating-point types
|
||||||
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
||||||
{
|
{
|
||||||
locale_switching_token token("2.25", comma_locale);
|
locale_switching_token token("2.25", comma_locale.c_str());
|
||||||
float value = 0;
|
float value = 0;
|
||||||
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
||||||
if (token.switched)
|
if (token.switched)
|
||||||
@@ -670,7 +670,7 @@ TEST_CASE("convert_float_locale_aware")
|
|||||||
}
|
}
|
||||||
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
REQUIRE(std::setlocale(LC_NUMERIC, "C") != nullptr);
|
||||||
{
|
{
|
||||||
locale_switching_token token("2.25", comma_locale);
|
locale_switching_token token("2.25", comma_locale.c_str());
|
||||||
long double value = 0;
|
long double value = 0;
|
||||||
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
nlohmann::detail::convert_float_locale_aware(token, 1, value);
|
||||||
if (token.switched)
|
if (token.switched)
|
||||||
|
|||||||
@@ -122,8 +122,7 @@ TEST_CASE("JSON text with std::byte")
|
|||||||
SECTION("invalid text")
|
SECTION("invalid text")
|
||||||
{
|
{
|
||||||
CHECK_FALSE(json::accept(to_bytes("[1,\n2,")));
|
CHECK_FALSE(json::accept(to_bytes("[1,\n2,")));
|
||||||
json _;
|
CHECK_THROWS_WITH_AS(json::parse(to_bytes("[1,\n2,")),
|
||||||
CHECK_THROWS_WITH_AS(_ = json::parse(to_bytes("[1,\n2,")),
|
|
||||||
"[json.exception.parse_error.101] parse error at line 2, column 3: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
|
"[json.exception.parse_error.101] parse error at line 2, column 3: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -541,7 +541,6 @@ TEST_CASE("object_key_index")
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::size_t> hashes;
|
std::vector<std::size_t> hashes;
|
||||||
hashes.reserve(initial);
|
|
||||||
for (std::size_t i = 0; i < initial; ++i)
|
for (std::size_t i = 0; i < initial; ++i)
|
||||||
{
|
{
|
||||||
hashes.push_back(hash_of(i));
|
hashes.push_back(hash_of(i));
|
||||||
|
|||||||
@@ -1533,7 +1533,7 @@ TEST_CASE("regression tests 1")
|
|||||||
{
|
{
|
||||||
my_json::object_t top = orig.get_ref<const my_json::object_t&>();
|
my_json::object_t top = orig.get_ref<const my_json::object_t&>();
|
||||||
top.at("x") = my_json::parse(R"({"a":{"b":1},"n":null,"arr":[10,20],"objs":[{"m":5},{"m":6}]})");
|
top.at("x") = my_json::parse(R"({"a":{"b":1},"n":null,"arr":[10,20],"objs":[{"m":5},{"m":6}]})");
|
||||||
return my_json(std::move(top)); // NOLINT(modernize-return-braced-init-list): {top} would be an array
|
return my_json(std::move(top));
|
||||||
};
|
};
|
||||||
|
|
||||||
SECTION("existing members")
|
SECTION("existing members")
|
||||||
|
|||||||
@@ -1009,7 +1009,7 @@ TEST_CASE("regression test - excessive binary container size honors allow_except
|
|||||||
// allow_exceptions=true (the default) must still throw exactly as before.
|
// allow_exceptions=true (the default) must still throw exactly as before.
|
||||||
// The exact message text is not checked here: on platforms where
|
// The exact message text is not checked here: on platforms where
|
||||||
// std::size_t is 32-bit, the CBOR reader's own length-narrowing check
|
// std::size_t is 32-bit, the CBOR reader's own length-narrowing check
|
||||||
// (get_cbor_container_size(), unrelated to this fix) intercepts a
|
// (get_container_size(), unrelated to this fix) intercepts a
|
||||||
// declared length of 2^63 before it ever reaches the check this test
|
// declared length of 2^63 before it ever reaches the check this test
|
||||||
// targets, with different (but equally valid, and already correct)
|
// targets, with different (but equally valid, and already correct)
|
||||||
// wording -- see unit-cbor.cpp for coverage of that message.
|
// wording -- see unit-cbor.cpp for coverage of that message.
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ class oversized_get_area_streambuf : public std::streambuf
|
|||||||
private:
|
private:
|
||||||
std::array<char, 8> m_data{{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}};
|
std::array<char, 8> m_data{{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'}};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// how a test reads from the stream
|
// how a test reads from the stream
|
||||||
@@ -464,18 +463,15 @@ TEST_CASE("parsing from a std::istream scans the get area in bulk")
|
|||||||
CHECK(token.empty());
|
CHECK(token.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SIZE_MAX > UINT32_MAX
|
|
||||||
// a get area larger than an int needs a 64-bit std::size_t (checked by the
|
|
||||||
// preprocessor, as a constant condition triggers MSVC's C4127)
|
|
||||||
SECTION("skipping more characters than gbump() takes at once")
|
SECTION("skipping more characters than gbump() takes at once")
|
||||||
{
|
{
|
||||||
// gbump() takes an int, but a get area can be larger
|
// gbump() takes an int, but a get area can be larger
|
||||||
const std::size_t claimed = std::size_t{3} << 30u;
|
const std::size_t claimed = sizeof(std::size_t) < 8 ? 0 : std::size_t{3} << 30u;
|
||||||
oversized_get_area_streambuf buf(claimed);
|
oversized_get_area_streambuf buf(claimed);
|
||||||
if (static_cast<std::size_t>(buf.in_avail()) != claimed)
|
if (claimed == 0 || static_cast<std::size_t>(buf.in_avail()) != claimed)
|
||||||
{
|
{
|
||||||
// a standard library whose streambuf stores the size of the get
|
// a 32-bit size_t, or a standard library whose streambuf stores
|
||||||
// area in an int (MSVC)
|
// the size of the get area in an int (MSVC)
|
||||||
MESSAGE("a get area larger than an int is not supported");
|
MESSAGE("a get area larger than an int is not supported");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -495,7 +491,6 @@ TEST_CASE("parsing from a std::istream scans the get area in bulk")
|
|||||||
buf.restore_get_area();
|
buf.restore_get_area();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SECTION("SAX parsing from a stream")
|
SECTION("SAX parsing from a stream")
|
||||||
|
|||||||
@@ -2385,6 +2385,18 @@ TEST_CASE("UBJSON optimized arrays of a valueless type are bounded")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("a count equal to SIZE_MAX is rejected")
|
||||||
|
{
|
||||||
|
// the reader marks a container without a count by SIZE_MAX, so a
|
||||||
|
// count of that value must not be read as "no count"; UBJSON's
|
||||||
|
// largest count type (int64) can only reach it where size_t is 32 bits
|
||||||
|
#if SIZE_MAX == 0xffffffff
|
||||||
|
const std::vector<uint8_t> input = {'[', '#', 'L', 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 'i', 0x01, ']'};
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(input), "[json.exception.out_of_range.408] syntax error while parsing UBJSON size: integer value overflow", json::out_of_range&);
|
||||||
|
CHECK(json::from_ubjson(input, true, false).is_discarded());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("ordinary counts are unaffected")
|
SECTION("ordinary counts are unaffected")
|
||||||
{
|
{
|
||||||
CHECK(json::from_ubjson(std::vector<uint8_t>({'[', '$', 'Z', '#', 'i', 3})) == json({nullptr, nullptr, nullptr}));
|
CHECK(json::from_ubjson(std::vector<uint8_t>({'[', '$', 'Z', '#', 'i', 3})) == json({nullptr, nullptr, nullptr}));
|
||||||
|
|||||||
Reference in new issue
Block a user