Skip to content

Accept numbers with huge exponents; never wrap the exponent - #486

Merged
Licenser merged 2 commits into
simd-lite:mainfrom
yuxi-liu-wired:pr/huge-exponent
Oct 4, 2026
Merged

Licenser merged 2 commits into
simd-lite:mainfrom
yuxi-liu-wired:pr/huge-exponent

Conversation

@yuxi-liu-wired

Copy link
Copy Markdown
Contributor

fix: accept numbers with huge exponents, never wrap the exponent

Two problems with exponents beyond 32 bits in the default (correct)
number parser:

  1. Rejected valid input. Once the exponent value passed 2^32 the next
    digit was an InvalidNumber error, so 0e99999999999,
    1e-99999999999 and [2e-44444044280] failed. RFC 8259 §6 puts no
    limit on the exponent; these are zero (serde_json and sonic-rs
    accept them; C++ simdjson saturates the exponent instead of
    failing). Now the exponent saturates and the remaining digits are
    still consumed.

  2. Wrong values. The exponent was passed on as exponent as i32, which
    wraps, so exponents just below the cutoff gave wrong finite numbers:

    1e4294967296    1.0      (now: error, out of range like 1e309)
    1e4294967295    0.1      (now: error)
    1e-4294967295   10.0     (now: 0.0)
    1.5e-8589934592 1.5      (now: 0.0)
    

    It now saturates to i32::MIN/MAX, which f64_from_parts already
    maps to 0 or to the out-of-range error.

Test: huge_exponent (fails before this change).

Testing

Each commit adds a regression test that fails before the change. The full test suite passes and
cargo fmt --check is clean on the changed files.

Found with a differential fuzzer comparing serde_json, simd-json, sonic-rs and jiter.

Comment thread src/numberparse/correct.rs Outdated
Comment thread src/numberparse/correct.rs
@Licenser
Licenser enabled auto-merge (squash) October 4, 2026 10:41
claude added 2 commits October 4, 2026 14:12
Two problems with exponents beyond 32 bits in the default (correct)
number parser:

1. Rejected valid input. Once the exponent value passed 2^32 the next
   digit was an `InvalidNumber` error, so `0e99999999999`,
   `1e-99999999999` and `[2e-44444044280]` failed. RFC 8259 §6 puts no
   limit on the exponent; these are zero (serde_json and sonic-rs
   accept them; C++ simdjson saturates the exponent instead of
   failing). Now the exponent saturates and the remaining digits are
   still consumed.

2. Wrong values. The exponent was passed on as `exponent as i32`, which
   wraps, so exponents just below the cutoff gave wrong finite numbers:

       1e4294967296    1.0      (now: error, out of range like 1e309)
       1e4294967295    0.1      (now: error)
       1e-4294967295   10.0     (now: 0.0)
       1.5e-8589934592 1.5      (now: 0.0)

   It now saturates to i32::MIN/MAX, which `f64_from_parts` already
   maps to 0 or to the out-of-range error.

Test: `huge_exponent` (fails before this change).

Found by a three-way differential fuzzer (serde_json, simd-json,
sonic-rs).
…iling garbage and + after a saturated exponent
@Licenser
Licenser merged commit b215cf0 into simd-lite:main Oct 4, 2026
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants