Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion src/uu/date/src/format_modifiers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gnu works with umax


/// Error type for format modifier operations
#[derive(Debug)]
pub enum FormatError {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}
}
10 changes: 9 additions & 1 deletion src/uu/false/src/false.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
10 changes: 9 additions & 1 deletion src/uu/true/src/true.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
24 changes: 19 additions & 5 deletions tests/by-util/test_date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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() {
Expand Down
10 changes: 10 additions & 0 deletions tests/by-util/test_false.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"] {
Expand Down
10 changes: 10 additions & 0 deletions tests/by-util/test_true.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"] {
Expand Down
Loading