Skip to content

seq, printf: avoid integer overflow on extreme precision/exponent#13246

Open
sylvestre wants to merge 2 commits into
uutils:mainfrom
sylvestre:precision
Open

seq, printf: avoid integer overflow on extreme precision/exponent#13246
sylvestre wants to merge 2 commits into
uutils:mainfrom
sylvestre:precision

Conversation

@sylvestre

Copy link
Copy Markdown
Contributor

Cap seq's float precision at i32::MAX (as printf already does) and reject values whose decimal exponent does not fit in i32 before the float formatters do exponent math, preventing the panic/wrap reported in #13221.

@codspeed-hq

codspeed-hq Bot commented Jul 1, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 4.89%

⚡ 1 improved benchmark
✅ 330 untouched benchmarks
⏩ 46 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation sort_ascii_utf8_locale 16.1 ms 15.4 ms +4.89%

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing sylvestre:precision (214a7e7) with main (51529dc)

Open in CodSpeed

Footnotes

  1. 46 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

Skip an intermittent issue tests/misc/io-errors (fails in this run but passes in the 'main' branch)
Skipping an intermittent issue tests/date/resolution (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/tail/tail-n0f (passes in this run but fails in the 'main' branch)
Note: The gnu test tests/cut/bounded-memory is now being skipped but was previously passing.
Note: The gnu test tests/cut/cut-huge-range is now being skipped but was previously passing.
Skip an intermittent issue tests/pr/bounded-memory (was skipped on 'main', now failing)

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR hardens seq/printf numeric formatting against arithmetic overflows triggered by extreme user-controlled precision and decimal exponents, addressing the panic/wrap scenarios reported in #13221.

Changes:

  • Centralize and apply a precision cap (i32::MAX) via a new check_precision helper across spec parsing and float formatter construction.
  • Reject floating-point inputs whose decimal exponent/scale is outside i32 before performing exponent/precision math in the float formatters.
  • Prevent overflow in seq -w padding computation via saturating arithmetic, and add regression tests for the overflow cases.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/by-util/test_seq.rs Adds regression tests for precision overflow rejection, exponent overflow rejection, and -w overflow avoidance.
tests/by-util/test_printf.rs Adds regression tests ensuring extreme exponents fail cleanly across %a/%e/%g/%f.
src/uucore/src/lib/features/format/spec.rs Replaces duplicated precision-limit checks with the shared check_precision helper.
src/uucore/src/lib/features/format/num_format.rs Adds exponent-range rejection for floats and adjusts hex-float computations to avoid overflow.
src/uucore/src/lib/features/format/mod.rs Introduces check_precision helper and unit tests for its behavior.
src/uu/seq/src/seq.rs Uses saturating arithmetic in equal-width padding to avoid overflow on extreme digit counts.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +153 to +159
pub(crate) fn check_precision(precision: usize) -> Result<(), FormatError> {
if precision as u64 > i32::MAX as u64 {
Err(FormatError::InvalidPrecision(precision.to_string()))
} else {
Ok(())
}
}
Comment thread tests/by-util/test_seq.rs
Comment on lines +62 to +69
fn test_equal_width_huge_exponent_does_not_overflow() {
// Equal-width padding adds the integral-digit count to the precision; a value
// with an astronomically large exponent must saturate instead of overflowing.
new_ucmd!()
.args(&["-w", "1e9223372036854775807", "1e-9223372036854775807", "1"])
.succeeds()
.no_stdout();
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think this test is incorrect because GNU seq fails:

$ seq -w 1e9223372036854775807 1e-9223372036854775807 1
seq: invalid floating point argument: ‘1e9223372036854775807’
Try 'seq --help' for more information.
$ echo $?
1

Comment thread tests/by-util/test_printf.rs Outdated
Comment on lines +810 to +814
new_ucmd!()
.args(&[spec, "5e8123456789012345678"])
.fails_with_code(1)
.no_stdout()
.stderr_contains("number too large to format");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

GNU printf prints inf to stdout in all four cases.

Comment thread tests/by-util/test_printf.rs Outdated
Comment on lines +816 to +820
new_ucmd!()
.args(&[spec, "7E-8123456789012345678"])
.fails_with_code(1)
.no_stdout()
.stderr_contains("number too large to format");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

GNU printf prints 0 in different formats on stdout.

Cap seq's float precision at i32::MAX (as printf already does) and reject
values whose decimal exponent does not fit in i32 before the float formatters
do exponent math, preventing the panic/wrap reported in uutils#13221.
…havior

The test asserted parsing succeeds for an exponent of exactly i64::MAX,
but the parser (correctly, matching GNU seq) already rejects it -- the
test's own expectation was wrong, not the parsing logic.
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