mirror of
https://github.com/nlohmann/json.git
synced 2026-07-23 10:54:53 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf14cbdd02 | ||
|
|
3565f40229 |
@@ -1846,6 +1846,47 @@ class binary_reader
|
||||
return get_ubjson_value(get_char ? get_ignore_noop() : current);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief reject a negative UBJSON/BJData string length
|
||||
|
||||
String and key lengths are written with signed integer markers (i, I, l,
|
||||
L). A negative value is malformed; without this check get_string() would
|
||||
silently treat it as an empty string and leave the following bytes to be
|
||||
misread as the next value. This mirrors the non-negative check the
|
||||
optimized-container count path already performs in get_ubjson_size_value.
|
||||
|
||||
@param[in] len the string length read from the input
|
||||
@return whether the length is valid (non-negative)
|
||||
*/
|
||||
template<typename NumberType>
|
||||
bool check_ubjson_string_length(const NumberType len)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(len < 0))
|
||||
{
|
||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
||||
exception_message(input_format, "string length must not be negative", "string"), nullptr));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief create the error message for a missing/invalid length-type marker
|
||||
|
||||
Used both when reading a UBJSON/BJData string and when reading an optimized
|
||||
container size. The accepted markers depend on the input format, and the
|
||||
size variant appends " after '#'" via @a infix.
|
||||
|
||||
@param[in] last_token the offending byte as returned by get_token_string()
|
||||
@param[in] infix extra context inserted after the marker list
|
||||
@return the formatted error message
|
||||
*/
|
||||
std::string unexpected_length_type_message(const std::string& last_token, const char* infix) const
|
||||
{
|
||||
return concat("expected length type specification (",
|
||||
input_format == input_format_t::bjdata ? "U, i, u, I, m, l, M, L" : "U, i, I, l, L",
|
||||
")", infix, "; last byte: 0x", last_token);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief reads a UBJSON string
|
||||
|
||||
@@ -1883,25 +1924,25 @@ class binary_reader
|
||||
case 'i':
|
||||
{
|
||||
std::int8_t len{};
|
||||
return get_number(input_format, len) && get_string(input_format, len, result);
|
||||
return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result);
|
||||
}
|
||||
|
||||
case 'I':
|
||||
{
|
||||
std::int16_t len{};
|
||||
return get_number(input_format, len) && get_string(input_format, len, result);
|
||||
return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result);
|
||||
}
|
||||
|
||||
case 'l':
|
||||
{
|
||||
std::int32_t len{};
|
||||
return get_number(input_format, len) && get_string(input_format, len, result);
|
||||
return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result);
|
||||
}
|
||||
|
||||
case 'L':
|
||||
{
|
||||
std::int64_t len{};
|
||||
return get_number(input_format, len) && get_string(input_format, len, result);
|
||||
return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result);
|
||||
}
|
||||
|
||||
case 'u':
|
||||
@@ -1938,17 +1979,8 @@ class binary_reader
|
||||
break;
|
||||
}
|
||||
auto last_token = get_token_string();
|
||||
std::string message;
|
||||
|
||||
if (input_format != input_format_t::bjdata)
|
||||
{
|
||||
message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
|
||||
}
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||
exception_message(input_format, unexpected_length_type_message(last_token, ""), "string"), nullptr));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -2227,17 +2259,8 @@ class binary_reader
|
||||
break;
|
||||
}
|
||||
auto last_token = get_token_string();
|
||||
std::string message;
|
||||
|
||||
if (input_format != input_format_t::bjdata)
|
||||
{
|
||||
message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
|
||||
}
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||
exception_message(input_format, unexpected_length_type_message(last_token, " after '#'"), "size"), nullptr));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -12395,6 +12395,47 @@ class binary_reader
|
||||
return get_ubjson_value(get_char ? get_ignore_noop() : current);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief reject a negative UBJSON/BJData string length
|
||||
|
||||
String and key lengths are written with signed integer markers (i, I, l,
|
||||
L). A negative value is malformed; without this check get_string() would
|
||||
silently treat it as an empty string and leave the following bytes to be
|
||||
misread as the next value. This mirrors the non-negative check the
|
||||
optimized-container count path already performs in get_ubjson_size_value.
|
||||
|
||||
@param[in] len the string length read from the input
|
||||
@return whether the length is valid (non-negative)
|
||||
*/
|
||||
template<typename NumberType>
|
||||
bool check_ubjson_string_length(const NumberType len)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(len < 0))
|
||||
{
|
||||
return sax->parse_error(chars_read, get_token_string(), parse_error::create(113, chars_read,
|
||||
exception_message(input_format, "string length must not be negative", "string"), nullptr));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief create the error message for a missing/invalid length-type marker
|
||||
|
||||
Used both when reading a UBJSON/BJData string and when reading an optimized
|
||||
container size. The accepted markers depend on the input format, and the
|
||||
size variant appends " after '#'" via @a infix.
|
||||
|
||||
@param[in] last_token the offending byte as returned by get_token_string()
|
||||
@param[in] infix extra context inserted after the marker list
|
||||
@return the formatted error message
|
||||
*/
|
||||
std::string unexpected_length_type_message(const std::string& last_token, const char* infix) const
|
||||
{
|
||||
return concat("expected length type specification (",
|
||||
input_format == input_format_t::bjdata ? "U, i, u, I, m, l, M, L" : "U, i, I, l, L",
|
||||
")", infix, "; last byte: 0x", last_token);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief reads a UBJSON string
|
||||
|
||||
@@ -12432,25 +12473,25 @@ class binary_reader
|
||||
case 'i':
|
||||
{
|
||||
std::int8_t len{};
|
||||
return get_number(input_format, len) && get_string(input_format, len, result);
|
||||
return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result);
|
||||
}
|
||||
|
||||
case 'I':
|
||||
{
|
||||
std::int16_t len{};
|
||||
return get_number(input_format, len) && get_string(input_format, len, result);
|
||||
return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result);
|
||||
}
|
||||
|
||||
case 'l':
|
||||
{
|
||||
std::int32_t len{};
|
||||
return get_number(input_format, len) && get_string(input_format, len, result);
|
||||
return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result);
|
||||
}
|
||||
|
||||
case 'L':
|
||||
{
|
||||
std::int64_t len{};
|
||||
return get_number(input_format, len) && get_string(input_format, len, result);
|
||||
return get_number(input_format, len) && check_ubjson_string_length(len) && get_string(input_format, len, result);
|
||||
}
|
||||
|
||||
case 'u':
|
||||
@@ -12487,17 +12528,8 @@ class binary_reader
|
||||
break;
|
||||
}
|
||||
auto last_token = get_token_string();
|
||||
std::string message;
|
||||
|
||||
if (input_format != input_format_t::bjdata)
|
||||
{
|
||||
message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
|
||||
}
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||
exception_message(input_format, unexpected_length_type_message(last_token, ""), "string"), nullptr));
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -12776,17 +12808,8 @@ class binary_reader
|
||||
break;
|
||||
}
|
||||
auto last_token = get_token_string();
|
||||
std::string message;
|
||||
|
||||
if (input_format != input_format_t::bjdata)
|
||||
{
|
||||
message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
|
||||
}
|
||||
else
|
||||
{
|
||||
message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
|
||||
}
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr));
|
||||
return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
|
||||
exception_message(input_format, unexpected_length_type_message(last_token, " after '#'"), "size"), nullptr));
|
||||
}
|
||||
|
||||
/*!
|
||||
|
||||
@@ -2721,6 +2721,19 @@ TEST_CASE("BJData")
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(v), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing BJData string: expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x31", json::parse_error&);
|
||||
}
|
||||
|
||||
SECTION("negative length")
|
||||
{
|
||||
json _;
|
||||
|
||||
std::vector<uint8_t> const vi = {'S', 'i', 0xFF};
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vi), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing BJData string: string length must not be negative", json::parse_error&);
|
||||
CHECK(json::from_bjdata(vi, true, false).is_discarded());
|
||||
|
||||
std::vector<uint8_t> const vl = {'S', 'l', 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vl), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing BJData string: string length must not be negative", json::parse_error&);
|
||||
CHECK(json::from_bjdata(vl, true, false).is_discarded());
|
||||
}
|
||||
|
||||
SECTION("parse bjdata markers in ubjson")
|
||||
{
|
||||
// create a single-character string for all number types
|
||||
|
||||
@@ -1862,6 +1862,31 @@ TEST_CASE("UBJSON")
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(v), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON string: expected length type specification (U, i, I, l, L); last byte: 0x31", json::parse_error&);
|
||||
}
|
||||
|
||||
SECTION("negative length")
|
||||
{
|
||||
json _;
|
||||
|
||||
std::vector<uint8_t> const vi = {'S', 'i', 0xFF};
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vi), "[json.exception.parse_error.113] parse error at byte 3: syntax error while parsing UBJSON string: string length must not be negative", json::parse_error&);
|
||||
CHECK(json::from_ubjson(vi, true, false).is_discarded());
|
||||
|
||||
std::vector<uint8_t> const vI = {'S', 'I', 0xFF, 0xFF};
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vI), "[json.exception.parse_error.113] parse error at byte 4: syntax error while parsing UBJSON string: string length must not be negative", json::parse_error&);
|
||||
CHECK(json::from_ubjson(vI, true, false).is_discarded());
|
||||
|
||||
std::vector<uint8_t> const vl = {'S', 'l', 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vl), "[json.exception.parse_error.113] parse error at byte 6: syntax error while parsing UBJSON string: string length must not be negative", json::parse_error&);
|
||||
CHECK(json::from_ubjson(vl, true, false).is_discarded());
|
||||
|
||||
std::vector<uint8_t> const vL = {'S', 'L', 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vL), "[json.exception.parse_error.113] parse error at byte 10: syntax error while parsing UBJSON string: string length must not be negative", json::parse_error&);
|
||||
CHECK(json::from_ubjson(vL, true, false).is_discarded());
|
||||
|
||||
// a length of zero remains valid and yields an empty string
|
||||
std::vector<uint8_t> const v0 = {'S', 'i', 0};
|
||||
CHECK(json::from_ubjson(v0) == json(""));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
|
||||
Reference in New Issue
Block a user