seq/printf: fix OOM abort in %a formatter for huge negative exponents#13370
Open
koopatroopa787 wants to merge 2 commits into
Open
seq/printf: fix OOM abort in %a formatter for huge negative exponents#13370koopatroopa787 wants to merge 2 commits into
koopatroopa787 wants to merge 2 commits into
Conversation
`seq -f %a 1E-1000000000000000000 1` aborted with: memory allocation of 375000000000000024 bytes failed Aborted (core dumped) The root cause is in `format_float_hexadecimal` (uucore): when the decimal exponent is very negative the formula margin ≈ -exp10 * 3 + (precision+1)*4 overflows to ~3×10¹⁸, so `frac10 << margin` asks num-bigint to build an integer of that many bits, exhausting memory. GNU `seq` uses a `long double` (≈15-bit exponent, ±4932 decade range), so values below ~10⁻⁴⁹³² naturally underflow to zero and are formatted as `0x0p+0`. Mirror that behaviour: if the decimal exponent is below −5000, return the zero representation immediately without entering the bignum path. Fixes uutils#13222
Contributor
|
Please fix the failing jobs |
|
GNU testsuite comparison: |
Two CI failures on uutils#13370: 1. cspell flagged 'bignum' as unknown — add it to the existing spell-checker:ignore directive in num_format.rs and inline in test_seq.rs. 2. test_format_a_huge_negative_exponent_does_not_oom timed out (>30s) because seq's BigDecimal arithmetic on a 10^18-scale number hangs before the formatter is even reached. Swap to 1E-5001: this value still exercises the early-exit guard (*num < -5000) but keeps the BigDecimal scale manageable (~5001-digit integers). The unit test in num_format.rs still covers the 1E-1000000000000000000 extreme case directly.
Contributor
Author
|
Fixed — two issues addressed in the latest push:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
seq -f %a 1E-1000000000000000000 1aborts with an out-of-memory error:The crash is in
format_float_hexadecimalinsideuucore. When the decimal exponentexp10is very negative, the formula:produces
margin ≈ 3 × 10¹⁸forexp10 = -10¹⁸. The subsequentfrac10 << marginasksnum-bigintto build an integer of that many bits (~375 petabytes), which the allocator rejects and the process aborts (exit 134).Root cause
GNU
sequses along double(80-bit on x86-64, exponent range ≈ ±4932). Any decimal value with magnitude smaller than ~10⁻⁴⁹³² underflows to0and is formatted as0x0p+0cheaply. The uutils bignum path has no such guard and tries to compute the exact binary representation regardless of the exponent magnitude.The existing code even has a TODO comment noting the hazard:
Fix
Add an early-exit before the bignum path in
format_float_hexadecimal: ifexp10 < -5000, the value underflows to zero in any long-double implementation, so return the zero hex-float representation immediately.The threshold 5000 is safely beyond the ±4932 decade range of 80-bit and 128-bit long double, so no representable nonzero value is incorrectly rounded to zero.
Tests
hexadecimal_float_huge_negative_exponent_does_not_oominnum_format.rs— verifies1E-1000000000000000000→0x0p+0and1E-5001→0x0p+0without panic/abort.test_format_a_huge_negative_exponent_does_not_oomintest_seq.rs— exercises the exact invocation from the bug report.Fixes #13222