From 423728495fa4bbb66c612d542934576aca96fe8e Mon Sep 17 00:00:00 2001 From: Coro Date: Tue, 11 Aug 2026 10:39:18 -0600 Subject: [PATCH] printf: avoid panic on i64::MIN dynamic field width A negative %*d width resolved its magnitude with -(nb as isize), which overflows for i64::MIN since it has no positive counterpart. Use unsigned_abs so the value is well defined; the magnitude exceeds the maximum width, so printf now fails cleanly instead of aborting. Adds a regression test. Fixes #13766. --- src/uucore/src/lib/features/format/spec.rs | 5 ++++- tests/by-util/test_printf.rs | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/uucore/src/lib/features/format/spec.rs b/src/uucore/src/lib/features/format/spec.rs index 1af75ae94d4..b30038d246d 100644 --- a/src/uucore/src/lib/features/format/spec.rs +++ b/src/uucore/src/lib/features/format/spec.rs @@ -511,7 +511,10 @@ fn resolve_asterisk_width( Some(CanAsterisk::Asterisk(loc)) => { let nb = args.next_i64(loc); if nb < 0 { - Some((usize::try_from(-(nb as isize)).ok().unwrap_or(0), true)) + // A negative width means left alignment; its magnitude is the + // width. Use unsigned_abs so that i64::MIN (which has no positive + // counterpart as an i64) does not overflow when negated. + Some((usize::try_from(nb.unsigned_abs()).ok().unwrap_or(0), true)) } else { Some((usize::try_from(nb).ok().unwrap_or(0), false)) } diff --git a/tests/by-util/test_printf.rs b/tests/by-util/test_printf.rs index 4ab67e128da..eb4350f974d 100644 --- a/tests/by-util/test_printf.rs +++ b/tests/by-util/test_printf.rs @@ -439,6 +439,17 @@ fn sub_min_width_negative() { .stdout_only("hello world "); } +#[test] +fn sub_asterisk_width_i64_min_no_panic() { + // A dynamic width of i64::MIN must not panic with "attempt to negate with + // overflow" (#13766). Its magnitude exceeds the maximum width, so printf + // fails cleanly with exit code 1 rather than aborting (which would be 134). + new_ucmd!() + .args(&["%*d", "-9223372036854775808", "1"]) + .fails_with_code(1) + .stderr_contains("width too large"); +} + #[test] fn sub_str_max_chars_input() { new_ucmd!()