mirror of
https://github.com/nlohmann/json.git
synced 2026-11-10 14:21:01 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61a37849c9 |
No files matched your search
@@ -393,7 +393,7 @@ struct depth_counter<false>
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief where the double x nearest to a token w * 10^q lies, for 10^15 <= w <
|
@brief where the double x nearest to a token w * 10^q lies, for 10^15 <= w <
|
||||||
10^17 and -17 <= q <= -1 (Eisel-Lemire, then a fixed-point position)
|
10^17 and -16 <= q <= -1 (Eisel-Lemire, then a fixed-point position)
|
||||||
|
|
||||||
dump() writes the shortest decimal in the rounding interval of x (the closest
|
dump() writes the shortest decimal in the rounding interval of x (the closest
|
||||||
one if there are several, see zmij::to_shortest()). Its digits are those of a
|
one if there are several, see zmij::to_shortest()). Its digits are those of a
|
||||||
@@ -1258,13 +1258,15 @@ class view_serializer
|
|||||||
}
|
}
|
||||||
for (; p != stop && batch.count != float_batch::capacity(); ++p)
|
for (; p != stop && batch.count != float_batch::capacity(); ++p)
|
||||||
{
|
{
|
||||||
// a token of the source: 16 or 17 digits, at least 8 after the
|
// a token of the source: 16 or 17 digits, 8 to 16 after the
|
||||||
// point, no exponent, 32 bytes to read
|
// point, no exponent, 32 bytes to read (17 after the point, with
|
||||||
|
// no digit before it, only in a damaged image loaded with
|
||||||
|
// image_check::bounds: beyond the range of locate_token())
|
||||||
const unsigned frac_digits = p->extra >> 8u;
|
const unsigned frac_digits = p->extra >> 8u;
|
||||||
const unsigned int_digits = p->extra & 0xFFu;
|
const unsigned int_digits = p->extra & 0xFFu;
|
||||||
const unsigned count = int_digits + frac_digits;
|
const unsigned count = int_digits + frac_digits;
|
||||||
if (p->kind == node_kind::number_float && (p->flags & node_flags::storage) == 0
|
if (p->kind == node_kind::number_float && (p->flags & node_flags::storage) == 0
|
||||||
&& count - 16u <= 1u && frac_digits >= 8 && src_end - (src + p->off) >= 33)
|
&& count - 16u <= 1u && frac_digits - 8u <= 8u && src_end - (src + p->off) >= 33)
|
||||||
{
|
{
|
||||||
const auto* const token = reinterpret_cast<const unsigned char*>(src + p->off); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
const auto* const token = reinterpret_cast<const unsigned char*>(src + p->off); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
const unsigned sign = token[0] == '-' ? 1 : 0;
|
const unsigned sign = token[0] == '-' ? 1 : 0;
|
||||||
|
|||||||
Generated
+6
-4
@@ -8841,7 +8841,7 @@ struct depth_counter<false>
|
|||||||
|
|
||||||
/*!
|
/*!
|
||||||
@brief where the double x nearest to a token w * 10^q lies, for 10^15 <= w <
|
@brief where the double x nearest to a token w * 10^q lies, for 10^15 <= w <
|
||||||
10^17 and -17 <= q <= -1 (Eisel-Lemire, then a fixed-point position)
|
10^17 and -16 <= q <= -1 (Eisel-Lemire, then a fixed-point position)
|
||||||
|
|
||||||
dump() writes the shortest decimal in the rounding interval of x (the closest
|
dump() writes the shortest decimal in the rounding interval of x (the closest
|
||||||
one if there are several, see zmij::to_shortest()). Its digits are those of a
|
one if there are several, see zmij::to_shortest()). Its digits are those of a
|
||||||
@@ -9706,13 +9706,15 @@ class view_serializer
|
|||||||
}
|
}
|
||||||
for (; p != stop && batch.count != float_batch::capacity(); ++p)
|
for (; p != stop && batch.count != float_batch::capacity(); ++p)
|
||||||
{
|
{
|
||||||
// a token of the source: 16 or 17 digits, at least 8 after the
|
// a token of the source: 16 or 17 digits, 8 to 16 after the
|
||||||
// point, no exponent, 32 bytes to read
|
// point, no exponent, 32 bytes to read (17 after the point, with
|
||||||
|
// no digit before it, only in a damaged image loaded with
|
||||||
|
// image_check::bounds: beyond the range of locate_token())
|
||||||
const unsigned frac_digits = p->extra >> 8u;
|
const unsigned frac_digits = p->extra >> 8u;
|
||||||
const unsigned int_digits = p->extra & 0xFFu;
|
const unsigned int_digits = p->extra & 0xFFu;
|
||||||
const unsigned count = int_digits + frac_digits;
|
const unsigned count = int_digits + frac_digits;
|
||||||
if (p->kind == node_kind::number_float && (p->flags & node_flags::storage) == 0
|
if (p->kind == node_kind::number_float && (p->flags & node_flags::storage) == 0
|
||||||
&& count - 16u <= 1u && frac_digits >= 8 && src_end - (src + p->off) >= 33)
|
&& count - 16u <= 1u && frac_digits - 8u <= 8u && src_end - (src + p->off) >= 33)
|
||||||
{
|
{
|
||||||
const auto* const token = reinterpret_cast<const unsigned char*>(src + p->off); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
const auto* const token = reinterpret_cast<const unsigned char*>(src + p->off); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||||
const unsigned sign = token[0] == '-' ? 1 : 0;
|
const unsigned sign = token[0] == '-' ? 1 : 0;
|
||||||
|
|||||||
@@ -1165,6 +1165,44 @@ TEST_CASE("json_view images: check")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("float tokens with 17 digits after the point and none before it")
|
||||||
|
{
|
||||||
|
// No JSON number has this layout. dump() batches tokens of 16 or 17
|
||||||
|
// digits, but only those with 8 to 16 fraction digits are in its
|
||||||
|
// range: 17 read past the table of powers of five (caught by a
|
||||||
|
// bounds-checked std::array), and on x86-64 wrote 18 digits
|
||||||
|
// (the assertion of write_decimal()).
|
||||||
|
const std::vector<std::uint8_t> img = json_document::parse("[1.2345678901234567]" + std::string(40, ' ')).save();
|
||||||
|
node n = node_at(img, 1);
|
||||||
|
REQUIRE(n.len == 18);
|
||||||
|
n.extra = 17u << 8u;
|
||||||
|
std::vector<std::uint8_t> b = img;
|
||||||
|
set_node(b, 1, n);
|
||||||
|
std::memcpy(b.data() + text_at(img) + n.off, ".99999999999999999", 18);
|
||||||
|
const json_document d = json_document::load(b, image_check::bounds);
|
||||||
|
const std::string dumped = d.root().dump();
|
||||||
|
CAPTURE(dumped)
|
||||||
|
CHECK(json::parse(dumped)[0].is_number());
|
||||||
|
CHECK(dumped == d.root().materialize().dump());
|
||||||
|
|
||||||
|
// (the input of OSS-Fuzz issue 583898810: the token is " " and
|
||||||
|
// 15 nines, then "1{")
|
||||||
|
const std::vector<std::uint8_t> fuzzed =
|
||||||
|
{
|
||||||
|
0x4E, 0x4A, 0x56, 0x49, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x07, 0x10, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39,
|
||||||
|
0x31, 0x7B, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
|
||||||
|
0x20, 0x20, 0x00, 0x00
|
||||||
|
};
|
||||||
|
CHECK(load_result(fuzzed, image_check::full) == check_failed);
|
||||||
|
const json_document f = json_document::load(fuzzed, image_check::bounds);
|
||||||
|
CHECK_NOTHROW(f.root().dump());
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("nodes that share a range")
|
SECTION("nodes that share a range")
|
||||||
{
|
{
|
||||||
// [big string, then n strings made to point to the big string]: every
|
// [big string, then n strings made to point to the big string]: every
|
||||||
|
|||||||
Reference in new issue
Block a user