Skip to content

Commit abcdcdc

Browse files
leeeweecakebaker
authored andcommitted
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.
1 parent e63cc0c commit abcdcdc

2 files changed

Lines changed: 50 additions & 16 deletions

File tree

src/uu/pr/src/pr.rs

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -582,22 +582,43 @@ fn build_options(
582582
let expand_tabs = matches
583583
.get_one::<String>(options::EXPAND_TABS)
584584
.map(|s| {
585-
s.chars().next().map_or(Ok(ExpandTabsOptions::default()), |c| {
586-
if c.is_ascii_digit() {
587-
s
588-
.parse()
589-
.map_err(|_e| PrError::EncounteredErrors { msg: format!("{}\n{}", translate!("pr-error-invalid-expand-tab-argument", "arg" => s), translate!("pr-try-help-message")) })
590-
.map(|width| ExpandTabsOptions{input_char: TAB, width})
591-
} else if s.len() > 1 {
592-
s[1..]
593-
.parse()
594-
.map_err(|_e| PrError::EncounteredErrors { msg: format!("{}\n{}", translate!("pr-error-invalid-expand-tab-argument", "arg" => &s[1..]), translate!("pr-try-help-message")) })
595-
.map(|width| ExpandTabsOptions{input_char: c, width})
596-
} else {
597-
Ok(ExpandTabsOptions{input_char: c, width: 8})
598-
}
599-
})
600-
}).transpose()?;
585+
s.chars()
586+
.next()
587+
.map_or(Ok(ExpandTabsOptions::default()), |c| {
588+
let invalid = |arg: &str| PrError::EncounteredErrors {
589+
msg: format!(
590+
"{}\n{}",
591+
translate!("pr-error-invalid-expand-tab-argument", "arg" => arg),
592+
translate!("pr-try-help-message")
593+
),
594+
};
595+
if c.is_ascii_digit() {
596+
let width: i32 = s.parse().map_err(|_e| invalid(s))?;
597+
if width <= 0 {
598+
return Err(invalid(s));
599+
}
600+
Ok(ExpandTabsOptions {
601+
input_char: TAB,
602+
width,
603+
})
604+
} else if s.len() > 1 {
605+
let width: i32 = s[1..].parse().map_err(|_e| invalid(&s[1..]))?;
606+
if width <= 0 {
607+
return Err(invalid(&s[1..]));
608+
}
609+
Ok(ExpandTabsOptions {
610+
input_char: c,
611+
width,
612+
})
613+
} else {
614+
Ok(ExpandTabsOptions {
615+
input_char: c,
616+
width: 8,
617+
})
618+
}
619+
})
620+
})
621+
.transpose()?;
601622

602623
let double_space = matches.get_flag(options::DOUBLE_SPACE);
603624

tests/by-util/test_pr.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -889,3 +889,16 @@ fn test_zero_columns_shortcut() {
889889
.fails_with_code(1)
890890
.stderr_contains("pr: invalid --column argument '0'");
891891
}
892+
893+
#[test]
894+
fn test_zero_expand_tab_width() {
895+
let expected = "pr: '-e' extra characters or invalid number in the argument: ‘0’\nTry 'pr --help' for more information.\n";
896+
new_ucmd!()
897+
.arg("-e0")
898+
.fails_with_code(1)
899+
.stderr_only(expected);
900+
new_ucmd!()
901+
.arg("-eX0")
902+
.fails_with_code(1)
903+
.stderr_only(expected);
904+
}

0 commit comments

Comments
 (0)