Skip to content

Reject unsafe unquoted integer floats#274

Merged
iainmcgin merged 2 commits into
anthropics:mainfrom
fallintoplace:fix/json-safe-int-f64
Jul 8, 2026
Merged

Reject unsafe unquoted integer floats#274
iainmcgin merged 2 commits into
anthropics:mainfrom
fallintoplace:fix/json-safe-int-f64

Conversation

@fallintoplace

Copy link
Copy Markdown
Contributor

Summary

  • reject high-magnitude unquoted decimal/exponent JSON numbers once they arrive as integer-valued f64s
  • keep exact quoted decimal/exponent strings working for full i64/u64 values
  • add regression coverage for the rounded 9007199254740993.0 and exponent forms, including negative i64 cases

Notes

visit_f64 does not expose the original JSON number text, so the parser may already have rounded before the integer visitor runs. The guard keeps small integer-valued float notation working while rejecting larger values that should be quoted for exact parsing.

Tests

  • cargo test -p buffa --all-features json_helpers::tests
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo test --workspace --all-features

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

The original comment justified the cutoff with f64 representability,
which is wrong at this boundary (integers are exact up to 2^53). The
actual hazard is serde_json's default float parsing, which is not
correctly rounded: from 2^52 a one-ulp parse error is a whole integer,
observed concretely as "9007199254740991.0" parsing to ...990.0. Below
2^52 the same error breaks integrality and the exactness check rejects
it loudly. Document that, pin the observed misparse as a reject test,
extend rejection coverage across [2^52, 2^53), drop two no-op
rustfmt::skip attributes, and rewrite the changelog fragment
accordingly with the PR reference.

No-Verification-Needed: doc/test-only fixups, bound value unchanged

@iainmcgin iainmcgin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[claude code] Thanks @fallintoplace — this fix is correct, and the review process turned up something worth recording: your constant was right for a reason the comment didn't state.

The original doc justified 2^52 - 1 via f64 spacing ("adjacent representable f64s are spaced at least one integer apart"), which is inaccurate at that boundary — every integer up to 2^53 is exactly representable, and our reviewer initially concluded the principled bound was 2^53 - 1 (Number.MAX_SAFE_INTEGER) and that the PR over-rejected a full binade. Moving the bound there failed empirically: "9007199254740991.0" (2^53 - 1, exactly representable) decodes to …990 — because serde_json's default float parsing is not correctly rounded (that's its opt-in float_roundtrip feature), and in [2^52, 2^53) a one-ulp parse error is a whole integer. Below 2^52 the same error breaks integrality and the existing exactness check rejects the token loudly instead of mis-decoding it. So 2^52 - 1 is exactly right for buffa's serde configuration.

Pushed as fe1b75e: the doc comment now states that real rationale (with the observed misparse as evidence), the reject tests pin "9007199254740991.0" and extend coverage across [2^52, 2^53), two no-op #[rustfmt::skip]s are dropped, and the changelog fragment is rewritten accordingly with the PR reference. The constant itself is unchanged from your version.

Residual limitation, documented rather than fixed: no f64-side bound can catch a non-integer token rounding to an integer ("1.0000000000000001"1 at any magnitude) — the complete fix would be serde_json's float_roundtrip or arbitrary_precision, which is a dependency-wide decision out of scope here.

Approving; will queue for merge once CI runs.

@iainmcgin iainmcgin added this pull request to the merge queue Jul 8, 2026
Merged via the queue into anthropics:main with commit 19b2c25 Jul 8, 2026
9 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 8, 2026
@iainmcgin

Copy link
Copy Markdown
Collaborator

[claude code] Merged as 19b2c25 — thanks @fallintoplace! This one was the most instructive review of the batch: your bound survived a challenge from our own reviewer, and the empirical check that settled it (serde_json's default parse rounding …991.0 down to …990) is now pinned as a regression test.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants