csplit: panic on overflow in `{N}` repetition count and `/regex/OFF` offset
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 24.1k
- Forks
- 2k
- Avg merge
- 1d 5h
- Merged PRs (30d)
- 365
Description
Affects: uutils/coreutils main (verified at commit aaf4a353c, 2026-05-28)
Severity: panic + abort on user-supplied input that GNU csplit rejects cleanly
Summary
csplit panics with a Rust backtrace instead of returning a clean error when
the user supplies a pattern argument whose embedded integer exceeds the target
type's range. Two distinct sites in src/uu/csplit/src/patterns.rs call
.unwrap() on a str::parse::<usize>() / str::parse::<i32>():
- line 123 — the
{N}repetition count - line 136 — the
/regex/OFF(and%regex%OFF) line offset
Reproduction
$ csplit - 1 '{99999999999999999999999999999999}' < /etc/hostname
thread 'main' panicked at src/uu/csplit/src/patterns.rs:123:83:
called `Result::unwrap()` on an `Err` value: ParseIntError { kind: PosOverflow }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Aborted (core dumped)
$ echo $?
134
$ csplit - '/x/-2147483649' < /etc/hostname
thread 'main' panicked at src/uu/csplit/src/patterns.rs:136:47:
called `Result::unwrap()` on an `Err` value: ParseIntError { kind: NegOverflow }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Aborted (core dumped)
$ echo $?
134
GNU coreutils 8.30 on the same inputs:
$ /usr/bin/csplit - 1 '{99999999999999999999999999999999}' < /etc/hostname
csplit: '{99999999999999999999999999999999'}: integer required between '{' and '}'
$ echo $?
1
$ /usr/bin/csplit - '/x/-2147483649' < /etc/hostname
csplit: '/x/-2147483649': line number out of range
$ echo $?
1
Offending code
src/uu/csplit/src/patterns.rs
// line 123 — {N} repetition count
if let Some(times) = r.name("TIMES") {
ExecutePattern::Times(times.as_str().parse::<usize>().unwrap() + 1)
} else { ... }
// line 136 — /regex/OFF offset
let offset = match captures.name("OFFSET") {
None => 0,
Some(m) => m.as_str().parse().unwrap(),
};
Both should propagate a CsplitError::InvalidPattern (or a more specific
variant) instead of unwrapping.
Suggested fix
// {N} repetition count
if let Some(times) = r.name("TIMES") {
let n: usize = times
.as_str()
.parse()
.map_err(|_| CsplitError::InvalidPattern(next_item.to_owned()))?;
ExecutePattern::Times(n.checked_add(1)
.ok_or_else(|| CsplitError::InvalidPattern(next_item.to_owned()))?)
} else { ExecutePattern::Always }
// /regex/OFF offset
let offset = match captures.name("OFFSET") {
None => 0,
Some(m) => m
.as_str()
.parse()
.map_err(|_| CsplitError::InvalidPattern(arg.to_owned()))?,
};
(The + 1 overflow on usize::MAX does not panic in release builds because
overflow checks are off — but it still produces silently wrong behavior
(Times(0)). The checked_add makes that a clean error in both profiles.)
Found by our static analysis tooling.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/uu/csplit/src/patterns.rs at the {N} repetition-count and /regex/OFF offset parsing sites, then run the two overflow reproductions from the issue. Done means both inputs return a clean csplit error matching the existing invalid-pattern behavior, without a panic or abort; include regression coverage if the surrounding tests support it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 84/100