Uh oh!
There was an error while loading. Please reload this page.
Guard displayExponent overflow in _toScientific (#185) - #245
Guard displayExponent overflow in _toScientific (#185)#245thedavidmeister wants to merge 7 commits into
Conversation
After maximizeFull, scaleExponent is 75 or 76. For Floats with large positive exponents (within ~76 of int32.max), displayExponent = exponent + scaleExponent exceeds int32.max, producing a formatted string whose exponent the parser cannot re-pack into int32. Revert with UnformatableExponent rather than silently emitting an un-parseable string. The negative-overflow case is also guarded but unreachable in practice: the minimum post-maximizeFull exponent from a valid Float is int32.min - 76, giving displayExponent = int32.min exactly (still in range). Two new tests pin the fix: one asserting the revert for (10, int32.max) and one confirming (1, int32.max) still formats successfully. Bytecode changes - requires manual-sol-artifacts redeploy before merge. Co-Authored-By: Claude <noreply@anthropic.com>
Update DecimalFloat artifact hash after displayExponent overflow guard.
Warning Review limit reached
Next review available in:54 minutes Limit details: You’ve used all 1 included review currently available under your plan. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
WalkthroughTwo unit tests are added to ChangesScientific displayExponent overflow tests
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Accept main's originalExponent approach in UnformatableExponent revert; update test to expect originalExponent (user-visible) instead of post-maximizeFull exponent. Co-Authored-By: Claude <noreply@anthropic.com>
…scientific-exponent-overflow
thedavidmeister
commented
Jul 5, 2026
Producer note: WAITING-DEPLOY (+1 inherited fuzz red). The 5 testProdDeployment* pins fail ('DecimalFloat not deployed') — same condition as main; needs the pre-merge deploy, not a code fix. The additional testRoundTripFuzzPow failure is the pre-existing #239 pow exponent-overflow bug hit by this run's fuzz seed — this PR only touches the _toScientific display path; the failure disappears once the #239 fix (#244 or #242) merges into this branch. |
thedavidmeister
commented
Jul 5, 2026
🤖 ai:producer |
thedavidmeister
commented
Jul 6, 2026
🤖 ai:producer |
🤖 ai:vetter |
thedavidmeister
commented
Jul 12, 2026
🤖 ai:producer |
thedavidmeister
commented
Aug 6, 2026
👤 human |
thedavidmeister
commented
Aug 6, 2026
Rework note @0dfd28c7b18c14d9ccc170105f6af5f347bd774a: rework the PR to fit the split release lifecycle — deploys never gate merges (the deploy-before-merge choreography is superseded); remove or restructure anything in the PR that waits on a deploy; where deploy constants/pins are involved, follow the *.deploy repo convention (audited code only; version ↔ snapshot ↔ pins internally consistent; tag-release lifecycle). Whatever states follow the rework (including a typed blocked-on the repo's migration if one is genuinely needed) are the producer's ordinary transitions. Executes the 2026-08-06 ruling: rainlanguage/issue-pr-cron#221 |
…scientific-exponent-overflow
thedavidmeister
commented
Aug 17, 2026
🤖 ai:producer |
…oy choreography rainix's `rainix-static agent-context-cap` gate (rainlanguage/rainix#298) is red on this repo: CLAUDE.md loaded 6593 bytes of agent context at every session start against a 4096-byte cap. Cut to 2346 bytes by dropping what foundry.toml, flake.nix and .github/workflows already say (build commands, layout, dependency list, compiler settings) and keeping only the hazards and rulings that are not recoverable from the code. The largest section cut is the superseded deploy-before-merge choreography — "trigger the Manual sol artifacts workflow on the PR's branch before merge", "do NOT wait for merge before deploying", and the claim that testDeployAddress and testExpectedCodeHashDecimalFloat gate a source-changing PR. Under the split release lifecycle a deploy is part of a release and never gates a merge, so that instruction is replaced by a statement of the rule it violated. The deploy constants' own tag-pinning convention is already documented in LibDecimalFloatDeploy.sol, where it is next to the constants it governs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
rainix's `rainix-static soldeer-gate` is red on this repo: foundry.toml [package].version was 0.1.7, which is already published to the soldeer registry (the registry lists 0.1.1 and 0.1.7). The next-version lifecycle requires the working version to be the next UNPUBLISHED one, so a release is a publish of what the tree already declares rather than a bump decided at release time. Bump only. Nothing is published by this change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary
_toScientificcomputesdisplayExponent = exponent + scaleExponentwherescaleExponentis 75 or 76 (frommaximizeFull). For validFloatvalues whose exponent is within ~76 ofint32.max,displayExponentoverflowsint32and the formatter emits a string the parser cannot re-pack — a silent data-corruption bug.UnformatableExponent(exponent)before emitting.testFormatScientificDisplayExponentOverflowReverts(exact reproduction of the bug with(10, int32.max)) andtestFormatScientificExponentAtMaxBoundarySucceeds(boundary:(1, int32.max)formats cleanly to"1e2147483647").Closes#185
This changes
LibFormatDecimalFloat, which is part of the deployedDecimalFloatcontract. ThetestDeployAddressandtestExpectedCodeHashDecimalFloatCI tests will fail until theManual sol artifactsworkflow is triggered on this branch:Test plan
testFormatScientificDisplayExponentOverflowReverts— new, confirms revert for the overflow casetestFormatScientificExponentAtMaxBoundarySucceeds— new, confirms the boundary value still formatsLibFormatDecimalFloatToDecimalStringTesttests still passtestFormatScientificDisplayExponentOverflowRevertsusesvm.expectRevert— removing the guard causes the test to fail🤖 Generated with Claude Code
Summary by CodeRabbit
QA
testFormatScientificDisplayExponentOverflowReverts,testFormatScientificExponentAtMaxBoundarySucceeds— neither fails on base, and that is the point: the_toScientificint32 guard itself already landed onmainvia fix: guard non-scientific formatter against positive-exp int224 overflow #243, so this PR is purely the regression coverage for it. Discrimination was verified against mutants of that guard instead (below), run in the checkout's ownnix develop …#sol-shelltoolchain.src/lib/format/LibFormatDecimalFloat.sol:108if (displayExponent > type(int32).max || displayExponent < type(int32).min)→if (false)→ killed bytestFormatScientificDisplayExponentOverflowReverts; same line>→>=→ killed bytestFormatScientificExponentAtMaxBoundarySucceedsalone (29 of the suite's 30 tests, including the pre-existingtestFormatScientificRevertsNearPositiveInt32Limit, survive it). Unmutated baseline: 30/30 pass.maximizeFullnormalises to a 76- or 77-digit coefficient, sodisplayExponent = exponent + (75|76).(10, int32.max): stored exponent drops 75, display shifts +76 →int32.max + 1, out of range.(1, int32.max): drops 76, shifts +76 →int32.maxexactly, in range, rendering"1e2147483647".displayExponentit cannot round-trip throughint32rather than silently emit an unparseable string; covered — the exact(10, int32.max)reproduction and the in-range(1, int32.max)upper boundary, the two cases the guard's own PR left unpinned.