diff --git a/src/uu/ptx/src/ptx.rs b/src/uu/ptx/src/ptx.rs index 510b6a2dbb6..1e400ceb3cf 100644 --- a/src/uu/ptx/src/ptx.rs +++ b/src/uu/ptx/src/ptx.rs @@ -199,6 +199,10 @@ struct WordRef { enum PtxError { #[error("{0}")] ParseError(ParseIntError), + #[error("invalid gap width: '{0}'")] + InvalidGapWidth(String), + #[error("invalid line width: '{0}'")] + InvalidLineWidth(String), } impl UError for PtxError {} @@ -246,20 +250,22 @@ fn get_config(matches: &mut clap::ArgMatches) -> UResult { .clone_into(&mut config.trunc_str); } if matches.contains_id(options::WIDTH) { - config.line_width = matches - .get_one::(options::WIDTH) - .expect(err_msg) - .parse() - .map_err(PtxError::ParseError)?; + let s = matches.get_one::(options::WIDTH).expect(err_msg); + let v: usize = s.parse().map_err(PtxError::ParseError)?; + if v > isize::MAX as usize { + return Err(PtxError::InvalidLineWidth(s.clone()).into()); + } + config.line_width = v; } else if matches.get_flag(options::TYPESET_MODE) { config.line_width = 100; } if matches.contains_id(options::GAP_SIZE) { - config.gap_size = matches - .get_one::(options::GAP_SIZE) - .expect(err_msg) - .parse() - .map_err(PtxError::ParseError)?; + let s = matches.get_one::(options::GAP_SIZE).expect(err_msg); + let v: usize = s.parse().map_err(PtxError::ParseError)?; + if v > isize::MAX as usize { + return Err(PtxError::InvalidGapWidth(s.clone()).into()); + } + config.gap_size = v; } if let Some(format) = matches.get_one::(options::FORMAT) { config.format = match format.as_str() { diff --git a/tests/by-util/test_ptx.rs b/tests/by-util/test_ptx.rs index 7a323e44d6c..ba8908988c6 100644 --- a/tests/by-util/test_ptx.rs +++ b/tests/by-util/test_ptx.rs @@ -425,3 +425,25 @@ fn test_invalid_regex_word_trailing_backslash() { fn test_invalid_regex_word_unclosed_group() { new_ucmd!().args(&["-W", "(wrong"]).succeeds().no_stderr(); } + +#[test] +fn test_gap_size_above_isize_max_is_rejected() { + // Values exceeding isize::MAX cause arithmetic overflow in the output + // chunk sizing; GNU ptx rejects them up front (#13184). + let too_big = format!("{}", isize::MAX as u64 + 1); + new_ucmd!() + .args(&["--gap-size", &too_big]) + .pipe_in("hello world\n") + .fails() + .stderr_contains("invalid gap width"); +} + +#[test] +fn test_line_width_above_isize_max_is_rejected() { + let too_big = format!("{}", isize::MAX as u64 + 1); + new_ucmd!() + .args(&["--width", &too_big]) + .pipe_in("hello world\n") + .fails() + .stderr_contains("invalid line width"); +}