From bc489511289fd17ec89b79a5ff957ab9990064a4 Mon Sep 17 00:00:00 2001 From: hum4nBeing Date: Fri, 31 Jul 2026 21:34:13 +0530 Subject: [PATCH] Fix UBJSON high-precision floating-point overflow handling (#5323) This adds a std::isfinite check to the UBJSON floating-point parsing path, throwing out_of_range.406 on overflow. This makes the UBJSON parser's behavior consistent with the normal JSON parser. Fixes #5322. Signed-off-by: AJ369ninja Co-authored-by: AJ369ninja --- include/nlohmann/detail/input/binary_reader.hpp | 12 +++++++++++- single_include/nlohmann/json.hpp | 12 +++++++++++- tests/src/unit-bjdata.cpp | 2 ++ tests/src/unit-ubjson.cpp | 2 ++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 8ec8436df..c37c603d3 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -2825,7 +2825,17 @@ class binary_reader case token_type::value_unsigned: return sax->number_unsigned(number_lexer.get_number_unsigned()); case token_type::value_float: - return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + { + const auto parsed_float = number_lexer.get_number_float(); + if (JSON_HEDLEY_UNLIKELY(!std::isfinite(parsed_float))) + { + return sax->parse_error( + chars_read, + number_string, + out_of_range::create(406, concat("number overflow parsing '", number_string, '\''), nullptr)); + } + return sax->number_float(parsed_float, std::move(number_string)); + } case token_type::uninitialized: case token_type::literal_true: case token_type::literal_false: diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index ec2651390..6e4d66258 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -13374,7 +13374,17 @@ class binary_reader case token_type::value_unsigned: return sax->number_unsigned(number_lexer.get_number_unsigned()); case token_type::value_float: - return sax->number_float(number_lexer.get_number_float(), std::move(number_string)); + { + const auto parsed_float = number_lexer.get_number_float(); + if (JSON_HEDLEY_UNLIKELY(!std::isfinite(parsed_float))) + { + return sax->parse_error( + chars_read, + number_string, + out_of_range::create(406, concat("number overflow parsing '", number_string, '\''), nullptr)); + } + return sax->number_float(parsed_float, std::move(number_string)); + } case token_type::uninitialized: case token_type::literal_true: case token_type::literal_false: diff --git a/tests/src/unit-bjdata.cpp b/tests/src/unit-bjdata.cpp index 4334f32d5..d00e1fa67 100644 --- a/tests/src/unit-bjdata.cpp +++ b/tests/src/unit-bjdata.cpp @@ -1347,6 +1347,8 @@ TEST_CASE("BJData") CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec2), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing BJData high-precision number: invalid number text: 1A", json::parse_error); std::vector const vec3 = {'H', 'i', 2, '1', '.'}; CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec3), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing BJData high-precision number: invalid number text: 1.", json::parse_error); + std::vector const vec_overflow = {'H', 'i', 5, '1', 'e', '4', '0', '0'}; + CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec_overflow), "[json.exception.out_of_range.406] number overflow parsing '1e400'", json::out_of_range); std::vector const vec4 = {'H', 2, '1', '0'}; CHECK_THROWS_WITH_AS(_ = json::from_bjdata(vec4), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing BJData size: expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x02", json::parse_error); } diff --git a/tests/src/unit-ubjson.cpp b/tests/src/unit-ubjson.cpp index 6df9acfac..d5668833d 100644 --- a/tests/src/unit-ubjson.cpp +++ b/tests/src/unit-ubjson.cpp @@ -819,6 +819,8 @@ TEST_CASE("UBJSON") CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vec2), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1A", json::parse_error); std::vector const vec3 = {'H', 'i', 2, '1', '.'}; CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vec3), "[json.exception.parse_error.115] parse error at byte 5: syntax error while parsing UBJSON high-precision number: invalid number text: 1.", json::parse_error); + std::vector const vec_overflow = {'H', 'i', 5, '1', 'e', '4', '0', '0'}; + CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vec_overflow), "[json.exception.out_of_range.406] number overflow parsing '1e400'", json::out_of_range&); std::vector const vec4 = {'H', 2, '1', '0'}; CHECK_THROWS_WITH_AS(_ = json::from_ubjson(vec4), "[json.exception.parse_error.113] parse error at byte 2: syntax error while parsing UBJSON size: expected length type specification (U, i, I, l, L) after '#'; last byte: 0x02", json::parse_error); }