diff options
| -rw-r--r-- | ext/json/parser/parser.c | 16 | ||||
| -rw-r--r-- | test/json/json_ryu_fallback_test.rb | 8 |
2 files changed, 20 insertions, 4 deletions
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index 38f3a48ce4..976fbbe757 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -855,7 +855,7 @@ NOINLINE(static) VALUE json_decode_large_float(const char *start, long len) /* Ruby JSON optimized float decoder using vendored Ryu algorithm * Accepts pre-extracted mantissa and exponent from first-pass validation */ -static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits, int32_t exponent, bool negative, +static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits, int64_t exponent, bool negative, const char *start, const char *end) { if (RB_UNLIKELY(config->decimal_class)) { @@ -863,13 +863,21 @@ static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantis return rb_funcallv(config->decimal_class, config->decimal_method_id, 1, &text); } + if (RB_UNLIKELY(exponent > INT32_MAX)) { + return CInfinity; + } + + if (RB_UNLIKELY(exponent < INT32_MIN)) { + return rb_float_new(0.0); + } + // Fall back to rb_cstr_to_dbl for potential subnormals (rare edge case) // Ryu has rounding issues with subnormals around 1e-310 (< 2.225e-308) if (RB_UNLIKELY(mantissa_digits > 17 || mantissa_digits + exponent < -307)) { return json_decode_large_float(start, end - start); } - return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, exponent, negative)); + return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, (int32_t)exponent, negative)); } static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count) @@ -1144,7 +1152,7 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig const char first_digit = *state->cursor; // Variables for Ryu optimization - extract digits during parsing - int32_t exponent = 0; + int64_t exponent = 0; int decimal_point_pos = -1; uint64_t mantissa = 0; @@ -1188,7 +1196,7 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig raise_parse_error_at("invalid number: %s", state, start); } - exponent = negative_exponent ? -((int32_t)abs_exponent) : ((int32_t)abs_exponent); + exponent = negative_exponent ? -abs_exponent : abs_exponent; } if (integer) { diff --git a/test/json/json_ryu_fallback_test.rb b/test/json/json_ryu_fallback_test.rb index 59ba76d392..dc60067b91 100644 --- a/test/json/json_ryu_fallback_test.rb +++ b/test/json/json_ryu_fallback_test.rb @@ -166,4 +166,12 @@ class JSONRyuFallbackTest < Test::Unit::TestCase end end end + + def test_large_exponent_numbers + assert_equal Float::INFINITY, JSON.parse("1e4294967296") + assert_equal 0.0, JSON.parse("1e-4294967296") + assert_equal 0.0, JSON.parse("99999999999999999e-4294967296") + assert_equal Float::INFINITY, JSON.parse("1e4294967295") + assert_equal Float::INFINITY, JSON.parse("1e4294967297") + end end |
