mirror of
https://github.com/nlohmann/json.git
synced 2026-06-06 20:59:44 +00:00
🐛 fix BSON conformance issue
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
@@ -170,7 +170,10 @@ class binary_reader
|
|||||||
bool parse_bson_internal()
|
bool parse_bson_internal()
|
||||||
{
|
{
|
||||||
std::int32_t document_size{};
|
std::int32_t document_size{};
|
||||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||||
{
|
{
|
||||||
@@ -181,9 +184,10 @@ class binary_reader
|
|||||||
"document size"), nullptr));
|
"document size"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// chars_read now points just past the 4-byte size field;
|
// The document begins at the size field and ends document_size bytes later
|
||||||
// the document started 4 bytes earlier and must end at start + document_size.
|
// (including the size field itself and the trailing 0x00 terminator).
|
||||||
const std::size_t expected_end = chars_read + static_cast<std::size_t>(document_size) - 4;
|
const std::size_t document_start = chars_read - sizeof(std::int32_t);
|
||||||
|
const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
|
||||||
{
|
{
|
||||||
@@ -434,7 +438,10 @@ class binary_reader
|
|||||||
bool parse_bson_array()
|
bool parse_bson_array()
|
||||||
{
|
{
|
||||||
std::int32_t document_size{};
|
std::int32_t document_size{};
|
||||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||||
{
|
{
|
||||||
@@ -445,9 +452,10 @@ class binary_reader
|
|||||||
"document size"), nullptr));
|
"document size"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// chars_read now points just past the 4-byte size field;
|
// The document begins at the size field and ends document_size bytes later
|
||||||
// the document started 4 bytes earlier and must end at start + document_size.
|
// (including the size field itself and the trailing 0x00 terminator).
|
||||||
const std::size_t expected_end = chars_read + static_cast<std::size_t>(document_size) - 4;
|
const std::size_t document_start = chars_read - sizeof(std::int32_t);
|
||||||
|
const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10312,7 +10312,10 @@ class binary_reader
|
|||||||
bool parse_bson_internal()
|
bool parse_bson_internal()
|
||||||
{
|
{
|
||||||
std::int32_t document_size{};
|
std::int32_t document_size{};
|
||||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||||
{
|
{
|
||||||
@@ -10323,9 +10326,10 @@ class binary_reader
|
|||||||
"document size"), nullptr));
|
"document size"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// chars_read now points just past the 4-byte size field;
|
// The document begins at the size field and ends document_size bytes later
|
||||||
// the document started 4 bytes earlier and must end at start + document_size.
|
// (including the size field itself and the trailing 0x00 terminator).
|
||||||
const std::size_t expected_end = chars_read + static_cast<std::size_t>(document_size) - 4;
|
const std::size_t document_start = chars_read - sizeof(std::int32_t);
|
||||||
|
const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_object(detail::unknown_size())))
|
||||||
{
|
{
|
||||||
@@ -10576,7 +10580,10 @@ class binary_reader
|
|||||||
bool parse_bson_array()
|
bool parse_bson_array()
|
||||||
{
|
{
|
||||||
std::int32_t document_size{};
|
std::int32_t document_size{};
|
||||||
get_number<std::int32_t, true>(input_format_t::bson, document_size);
|
if (JSON_HEDLEY_UNLIKELY((!get_number<std::int32_t, true>(input_format_t::bson, document_size))))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
if (JSON_HEDLEY_UNLIKELY(document_size < 5))
|
||||||
{
|
{
|
||||||
@@ -10587,9 +10594,10 @@ class binary_reader
|
|||||||
"document size"), nullptr));
|
"document size"), nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// chars_read now points just past the 4-byte size field;
|
// The document begins at the size field and ends document_size bytes later
|
||||||
// the document started 4 bytes earlier and must end at start + document_size.
|
// (including the size field itself and the trailing 0x00 terminator).
|
||||||
const std::size_t expected_end = chars_read + static_cast<std::size_t>(document_size) - 4;
|
const std::size_t document_start = chars_read - sizeof(std::int32_t);
|
||||||
|
const std::size_t expected_end = document_start + static_cast<std::size_t>(document_size);
|
||||||
|
|
||||||
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
|
if (JSON_HEDLEY_UNLIKELY(!sax->start_array(detail::unknown_size())))
|
||||||
{
|
{
|
||||||
|
|||||||
+35
-1
@@ -1302,6 +1302,7 @@ TEST_CASE("Invalid document size handling")
|
|||||||
std::vector<std::uint8_t> const v = {0x04, 0x00, 0x00, 0x00, 0x00};
|
std::vector<std::uint8_t> const v = {0x04, 0x00, 0x00, 0x00, 0x00};
|
||||||
json _;
|
json _;
|
||||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 4: syntax error while parsing BSON document size: BSON document size must be at least 5, is 4", json::parse_error&);
|
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 4: syntax error while parsing BSON document size: BSON document size must be at least 5, is 4", json::parse_error&);
|
||||||
|
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("declared document size must match consumed bytes (extra trailing element)")
|
SECTION("declared document size must match consumed bytes (extra trailing element)")
|
||||||
@@ -1316,6 +1317,38 @@ TEST_CASE("Invalid document size handling")
|
|||||||
};
|
};
|
||||||
json _;
|
json _;
|
||||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 16: syntax error while parsing BSON document: BSON document terminator did not land at declared document size", json::parse_error&);
|
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 16: syntax error while parsing BSON document: BSON document terminator did not land at declared document size", json::parse_error&);
|
||||||
|
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("declared document size must match consumed bytes (premature terminator)")
|
||||||
|
{
|
||||||
|
// Declares 32-byte document but only contains the size field followed by an immediate terminator.
|
||||||
|
std::vector<std::uint8_t> const v =
|
||||||
|
{
|
||||||
|
0x20, 0x00, 0x00, 0x00,
|
||||||
|
0x00
|
||||||
|
};
|
||||||
|
json _;
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 5: syntax error while parsing BSON document: BSON document terminator did not land at declared document size", json::parse_error&);
|
||||||
|
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("array declared size must match consumed bytes")
|
||||||
|
{
|
||||||
|
// Outer object contains an array "a" that declares 5 bytes (empty) but
|
||||||
|
// actually contains an int32 element before its terminator.
|
||||||
|
std::vector<std::uint8_t> const v =
|
||||||
|
{
|
||||||
|
0x14, 0x00, 0x00, 0x00, // object size = 20
|
||||||
|
0x04, 'a', 0x00, // key "a", array type
|
||||||
|
0x05, 0x00, 0x00, 0x00, // array declared size = 5 (empty)
|
||||||
|
0x10, '0', 0x00, 0x01, 0x00, 0x00, 0x00, // extra int32 element "0" = 1
|
||||||
|
0x00, // array terminator
|
||||||
|
0x00 // object terminator
|
||||||
|
};
|
||||||
|
json _;
|
||||||
|
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 19: syntax error while parsing BSON document: BSON document terminator did not land at declared document size", json::parse_error&);
|
||||||
|
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("BSON string must end with 0x00")
|
SECTION("BSON string must end with 0x00")
|
||||||
@@ -1331,5 +1364,6 @@ TEST_CASE("Invalid document size handling")
|
|||||||
};
|
};
|
||||||
json _;
|
json _;
|
||||||
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 13: syntax error while parsing BSON string: BSON string is not null-terminated", json::parse_error&);
|
CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 13: syntax error while parsing BSON string: BSON string is not null-terminated", json::parse_error&);
|
||||||
|
CHECK(json::from_bson(v, true, false).is_discarded());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user