diff --git a/include/nlohmann/detail/view/serializer.hpp b/include/nlohmann/detail/view/serializer.hpp index 8ed9fc9ac..9fc654544 100644 --- a/include/nlohmann/detail/view/serializer.hpp +++ b/include/nlohmann/detail/view/serializer.hpp @@ -752,9 +752,14 @@ class view_serializer { *w = '-'; w += d.negative ? 1 : 0; - // (without leading zeros, all digits of the token count) - const unsigned char lead = first[d.negative ? 1 : 0]; - return lead != '0' ? ::nlohmann::detail::dtoa_impl::write_short_decimal(w, d.w, static_cast(int_digits + frac_digits), static_cast(d.exponent)) + // (without leading zeros, all digits of the token count; the + // check also keeps an image that was only checked for bounds, + // whose token may not be made of digits, from the counted + // overload) + const auto& powers = ::nlohmann::detail::dtoa_impl::powers_of_ten_16(); + const unsigned count = int_digits + frac_digits; + return count - 1u < 15u && d.w >= powers[count - 1u] && d.w < powers[count] + ? ::nlohmann::detail::dtoa_impl::write_short_decimal(w, d.w, static_cast(count), static_cast(d.exponent)) : ::nlohmann::detail::dtoa_impl::write_short_decimal(w, d.w, static_cast(d.exponent)); } return write_double_value_at(w, decimal_to_float(d)); // (without reading the token again) diff --git a/tests/src/unit-json_view_image.cpp b/tests/src/unit-json_view_image.cpp index 6a615f7d4..eb511f52b 100644 --- a/tests/src/unit-json_view_image.cpp +++ b/tests/src/unit-json_view_image.cpp @@ -712,6 +712,31 @@ TEST_CASE("json_view images: check") } } + SECTION("float tokens with fewer digits than the layout records") + { + // The bytes of the token are not digits (they read as zeros or as + // other values), so the value has fewer (or more) digits than the + // layout says: dump() must still write a number. + for (const auto& source : std::vector> + { + {"123456789012345678.5", std::string("@") + std::string(16, '0') + "1.1"}, // 19 digits + {"1234.5", "@001.1"}, // 5 digits + {"1234.5", "9??.??"} // more than 5 digits + }) + { + CAPTURE(source.second) + const std::vector img = json_document::parse("[" + source.first + "]").save(); + const node n = node_at(img, 1); + REQUIRE(source.second.size() == n.len); + std::vector b = img; + std::memcpy(b.data() + text_at(img) + n.off, source.second.data(), n.len); + 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()); + } + } + SECTION("integer ranges") { // tokens of many digits, which the parser stores as floats