pr: reject a non-positive expand-tab width (-e0)

`pr -e0` on input containing a tab aborted with a remainder-by-zero panic
(`chunk.len() % expand_options.width` in `apply_expand_tab`). The
`-e[char][width]` parser accepted a width of `0` — and a negative width via
e.g. `-eX-5` — without validation, so the zero/negative reached the chunk
arithmetic.

Reject `width <= 0` while parsing `-e`, emitting the same invalid-argument
error GNU produces (`pr: '-e' extra characters or invalid number in the
argument: '0'`, exit 1) instead of crashing.
This commit is contained in:
weili
2026-06-05 04:47:40 +00:00
committed by Daniel Hofstetter
parent e63cc0c260
commit abcdcdca53
2 changed files with 50 additions and 16 deletions
+37 -16
View File
@@ -582,22 +582,43 @@ fn build_options(
let expand_tabs = matches
.get_one::<String>(options::EXPAND_TABS)
.map(|s| {
s.chars().next().map_or(Ok(ExpandTabsOptions::default()), |c| {
if c.is_ascii_digit() {
s
.parse()
.map_err(|_e| PrError::EncounteredErrors { msg: format!("{}\n{}", translate!("pr-error-invalid-expand-tab-argument", "arg" => s), translate!("pr-try-help-message")) })
.map(|width| ExpandTabsOptions{input_char: TAB, width})
} else if s.len() > 1 {
s[1..]
.parse()
.map_err(|_e| PrError::EncounteredErrors { msg: format!("{}\n{}", translate!("pr-error-invalid-expand-tab-argument", "arg" => &s[1..]), translate!("pr-try-help-message")) })
.map(|width| ExpandTabsOptions{input_char: c, width})
} else {
Ok(ExpandTabsOptions{input_char: c, width: 8})
}
})
}).transpose()?;
s.chars()
.next()
.map_or(Ok(ExpandTabsOptions::default()), |c| {
let invalid = |arg: &str| PrError::EncounteredErrors {
msg: format!(
"{}\n{}",
translate!("pr-error-invalid-expand-tab-argument", "arg" => arg),
translate!("pr-try-help-message")
),
};
if c.is_ascii_digit() {
let width: i32 = s.parse().map_err(|_e| invalid(s))?;
if width <= 0 {
return Err(invalid(s));
}
Ok(ExpandTabsOptions {
input_char: TAB,
width,
})
} else if s.len() > 1 {
let width: i32 = s[1..].parse().map_err(|_e| invalid(&s[1..]))?;
if width <= 0 {
return Err(invalid(&s[1..]));
}
Ok(ExpandTabsOptions {
input_char: c,
width,
})
} else {
Ok(ExpandTabsOptions {
input_char: c,
width: 8,
})
}
})
})
.transpose()?;
let double_space = matches.get_flag(options::DOUBLE_SPACE);
+13
View File
@@ -889,3 +889,16 @@ fn test_zero_columns_shortcut() {
.fails_with_code(1)
.stderr_contains("pr: invalid --column argument '0'");
}
#[test]
fn test_zero_expand_tab_width() {
let expected = "pr: '-e' extra characters or invalid number in the argument: 0\nTry 'pr --help' for more information.\n";
new_ucmd!()
.arg("-e0")
.fails_with_code(1)
.stderr_only(expected);
new_ucmd!()
.arg("-eX0")
.fails_with_code(1)
.stderr_only(expected);
}