diff --git a/src/uu/date/src/format_modifiers.rs b/src/uu/date/src/format_modifiers.rs index c6a3d01c857..c5139fc65d0 100644 --- a/src/uu/date/src/format_modifiers.rs +++ b/src/uu/date/src/format_modifiers.rs @@ -33,12 +33,16 @@ //! - `%^B`: Month name in uppercase (JUNE) //! - `%+4C`: Century with sign, padded to 4 characters (+019) -use jiff::Zoned; use jiff::fmt::strtime::{BrokenDownTime, Config, PosixCustom}; +use jiff::Zoned; use regex::Regex; use std::fmt; use std::sync::OnceLock; +/// Maximum allowed width for format modifiers to prevent memory exhaustion +/// This is an arbitrary reasonable limit - GNU date doesn't document a specific limit +const MAX_WIDTH: usize = 1024; + /// Error type for format modifier operations #[derive(Debug)] pub enum FormatError { @@ -145,7 +149,9 @@ fn format_with_modifiers( // Check if this specifier has modifiers if !flags.is_empty() || !width_str.is_empty() { // Apply modifiers to the formatted value + // Cap width at MAX_WIDTH to prevent memory exhaustion from extreme values let width: usize = width_str.parse().unwrap_or(0); + let width = width.min(MAX_WIDTH); let modified = apply_modifiers(&formatted, flags, width, spec); result.push_str(&modified); } else { @@ -566,4 +572,20 @@ mod tests { ); } } + + #[test] + fn test_extreme_width_no_panic() { + // Regression test for issue #11044 + // Extremely large width values should not cause panic + let date = make_test_date(1999, 6, 1, 0); + let config = get_config(); + + // This should succeed without panicking + let result = format_with_modifiers(&date, "%9223372036854775807Y", &config); + assert!(result.is_ok()); + + // Result should be capped at MAX_WIDTH + let result_str = result.unwrap(); + assert!(result_str.len() <= MAX_WIDTH); + } } diff --git a/src/uu/false/src/false.rs b/src/uu/false/src/false.rs index b0ade6957bc..421a94aa406 100644 --- a/src/uu/false/src/false.rs +++ b/src/uu/false/src/false.rs @@ -40,9 +40,17 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } pub fn uu_app() -> Command { + // Custom help template that puts Usage first (matching GNU coreutils) + // The default template shows about first, but GNU true/false show Usage first + let usage_label = uucore::locale::translate!("common-usage"); + let help_template = format!( + "{usage_label}: {{usage}}\n\n{about}\n\n{{all-args}}", + about = translate!("false-about") + ); + Command::new(uucore::util_name()) .version(uucore::crate_version!()) - .help_template(uucore::localized_help_template(uucore::util_name())) + .help_template(help_template) .about(translate!("false-about")) // We provide our own help and version options, to ensure maximum compatibility with GNU. .disable_help_flag(true) diff --git a/src/uu/true/src/true.rs b/src/uu/true/src/true.rs index fe8c762e0ec..56d54b496ee 100644 --- a/src/uu/true/src/true.rs +++ b/src/uu/true/src/true.rs @@ -39,9 +39,17 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } pub fn uu_app() -> Command { + // Custom help template that puts Usage first (matching GNU coreutils) + // The default template shows about first, but GNU true/false show Usage first + let usage_label = uucore::locale::translate!("common-usage"); + let help_template = format!( + "{usage_label}: {{usage}}\n\n{about}\n\n{{all-args}}", + about = translate!("true-about") + ); + Command::new(uucore::util_name()) .version(uucore::crate_version!()) - .help_template(uucore::localized_help_template(uucore::util_name())) + .help_template(help_template) .about(translate!("true-about")) // We provide our own help and version options, to ensure maximum compatibility with GNU. .disable_help_flag(true) diff --git a/tests/by-util/test_date.rs b/tests/by-util/test_date.rs index 1471634df37..7a173d09121 100644 --- a/tests/by-util/test_date.rs +++ b/tests/by-util/test_date.rs @@ -481,11 +481,9 @@ fn test_date_set_mac_unavailable() { .arg("2020-03-11 21:45:00+08:00") .fails(); result.no_stdout(); - assert!( - result - .stderr_str() - .starts_with("date: setting the date is not supported by macOS") - ); + assert!(result + .stderr_str() + .starts_with("date: setting the date is not supported by macOS")); } #[test] @@ -2334,6 +2332,22 @@ fn test_date_format_modifier_percent_escape() { .stdout_is("%Y=0000001999\n"); } +#[test] +fn test_date_format_modifier_extreme_width() { + // Regression test for issue #11044 + // Extremely large width values should not cause panic + new_ucmd!() + .env("TZ", "UTC") + .args(&["-d", "1999-06-01", "+%9223372036854775807Y"]) + .succeeds(); + + // Also test with other specifiers + new_ucmd!() + .env("TZ", "UTC") + .args(&["-d", "1999-06-01", "+%9999999999999999999m"]) + .succeeds(); +} + // Tests for --debug flag #[test] fn test_date_debug_basic() { diff --git a/tests/by-util/test_false.rs b/tests/by-util/test_false.rs index cc0874256b1..03af69e0675 100644 --- a/tests/by-util/test_false.rs +++ b/tests/by-util/test_false.rs @@ -27,6 +27,16 @@ fn test_help() { .stdout_contains("false"); } +#[test] +fn test_help_starts_with_usage() { + let result = new_ucmd!().arg("--help").fails(); + assert!( + result.stdout_str().starts_with("Usage: false"), + "unexpected --help output:\n{}", + result.stdout_str() + ); +} + #[test] fn test_short_options() { for option in ["-h", "-V"] { diff --git a/tests/by-util/test_true.rs b/tests/by-util/test_true.rs index 23c947fb29c..2a677d79972 100644 --- a/tests/by-util/test_true.rs +++ b/tests/by-util/test_true.rs @@ -30,6 +30,16 @@ fn test_help() { .stdout_contains("true"); } +#[test] +fn test_help_starts_with_usage() { + let result = new_ucmd!().arg("--help").succeeds(); + assert!( + result.stdout_str().starts_with("Usage: true"), + "unexpected --help output:\n{}", + result.stdout_str() + ); +} + #[test] fn test_short_options() { for option in ["-h", "-V"] {