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.
Affects: uutils/coreutils
main(verified at commitaaf4a353c, 2026-05-28)Severity: panic + abort on user-supplied input that GNU csplit rejects cleanly
Summary
csplitpanics with a Rust backtrace instead of returning a clean error whenthe user supplies a pattern argument whose embedded integer exceeds the target
type's range. Two distinct sites in
src/uu/csplit/src/patterns.rscall.unwrap()on astr::parse::<usize>()/str::parse::<i32>():{N}repetition count/regex/OFF(and%regex%OFF) line offsetReproduction
GNU coreutils 8.30 on the same inputs:
Offending code
src/uu/csplit/src/patterns.rsBoth should propagate a
CsplitError::InvalidPattern(or a more specificvariant) instead of unwrapping.
Suggested fix
(The
+ 1overflow onusize::MAXdoes not panic in release builds becauseoverflow checks are off — but it still produces silently wrong behavior
(
Times(0)). Thechecked_addmakes that a clean error in both profiles.)Found by our static analysis tooling.