Skip to content

split: keep a suffix start at the top of the range from overflowing - #14297

Open
arbelonson-source wants to merge 2 commits into
uutils:mainfrom
arbelonson-source:fix/split-suffix-start-overflow
Open

split: keep a suffix start at the top of the range from overflowing#14297
arbelonson-source wants to merge 2 commits into
uutils:mainfrom
arbelonson-source:fix/split-suffix-start-overflow

Conversation

@arbelonson-source

Copy link
Copy Markdown
Contributor

Fixes #13749.

split works out how wide the suffixes need to be from the start value plus the number of chunks. Either of those on its own can be as large as the type allows, so their sum is not always a value the type can hold:

$ split -n 5 --numeric-suffixes=18446744073709551615 /dev/null
thread 'main' panicked at src/uu/split/src/filenames.rs:202:36:
attempt to add with overflow

$ split -n 5 --hex-suffixes=ffffffffffffffff /dev/null
thread 'main' panicked at src/uu/split/src/filenames.rs:202:36:
attempt to add with overflow

With overflow checks off the add wraps instead, and the width computed from the wrapped sum is too small. Adding in u128 leaves room for the sum, so the width comes out right and the value is refused the way any other too-wide start already is:

$ split -n 5 --numeric-suffixes=18446744073709551615 /dev/null
split: the suffix length needs to be at least 20
$ split -n 5 --hex-suffixes=ffffffffffffffff /dev/null
split: the suffix length needs to be at least 16

@leeewee's report also names a third route to the same add — a huge -n with a nonzero start — and that one stops panicking too.

Scope

This is the panic only. Two neighbouring differences are left alone, and neither is touched by the change:

  • The wording differs from GNU for a start that is too wide, whether or not it overflows: GNU says numerical suffix start value is too large for the suffix length, we say the suffix length needs to be at least N. split -n 5 --numeric-suffixes=99999 already showed that on main, with no overflow involved.
  • Given a wide enough -a, GNU carries the suffix past u64 (x18446744073709551616, and for hex it walks the ASCII past f into xfffffffffffffff:); our FixedWidthNumber is u64-backed and stops with output file suffixes exhausted. Before this change that case panicked, so it is an improvement rather than a match.

Testing

  • Old-vs-new comparison over 509 invocations-n/-l/-b/-C/-n l/N/-n r/N crossed with --numeric-suffixes/--hex-suffixes at starts from 0 to 99999, -a from 1 to 10, -d, -x and --additional-suffix, comparing stdout, stderr, exit code and the resulting file names: 509 identical, 0 changed. Nothing in range moves.
  • The out-of-range cases were checked against GNU 9.11 individually; all now exit 1 with a message instead of aborting.
  • New test_suffix_start_at_the_top_of_the_range, verified to fail on main.
  • cargo test --features split --test tests -- test_split: 141 passed, 0 failed (140 pre-existing, 1 new); cargo test -p uu_split: 23 passed.
  • cargo fmt --check and cargo clippy -p uu_split --all-targets -- -D warnings: clean.

Disclosure

Prepared with AI assistance (Claude Opus 5, via Claude Code), per the AI policy in CONTRIBUTING.md. GNU's behaviour was established by running the installed GNU binary as a black box; I did not read GNU coreutils source. All testing was run locally.

`split` works out how wide the suffixes need to be from the start value
plus the number of chunks. Either of those on its own can be as large as
the type allows, so their sum is not always a value the type can hold:

    $ split -n 5 --numeric-suffixes=18446744073709551615 /dev/null
    thread 'main' panicked at src/uu/split/src/filenames.rs:202:36:
    attempt to add with overflow

    $ split -n 5 --hex-suffixes=ffffffffffffffff /dev/null
    thread 'main' panicked at src/uu/split/src/filenames.rs:202:36:
    attempt to add with overflow

With overflow checks off the add wraps instead, and the width computed
from the wrapped sum is too small.

Add in a type with room for the sum. The width then comes out right, and
the value is refused the way any other too-wide start is:

    $ split -n 5 --numeric-suffixes=18446744073709551615 /dev/null
    split: the suffix length needs to be at least 20

Fixes uutils#13749.
@github-actions

github-actions Bot commented Aug 31, 2026

Copy link
Copy Markdown

GNU testsuite comparison:

Skipping an intermittent issue tests/cut/bounded-memory (passes in this run but fails in the 'main' branch)
Skipping an intermittent issue tests/date/date-locale-hour (passes in this run but fails in the 'main' branch)
Note: The gnu test tests/basenc/bounded-memory is now being skipped but was previously passing.
Note: The gnu test tests/cp/link-heap is now being skipped but was previously passing.
Skip an intermittent issue tests/pr/bounded-memory (was skipped on 'main', now failing)

CI failed this test on i686 (and i686 windows): the start value
`18446744073709551615` is `u64::MAX`, which does not fit in a 32-bit
`usize`, so `--numeric-suffixes` rejects it at the parse step there
with a different message than the overflow-guard one this test checks.

The overflow this test exists for can only occur once `start` itself
reaches `u64::MAX`, which requires a 64-bit `usize` to hold in the
first place -- so on a 32-bit target there is nothing here left to
overflow, and the test doesn't apply.
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.

split: arithmetic overflow (overflow-checks) on a huge --numeric-suffixes/--hex-suffixes start value

1 participant