From 8b04fdc6026d6fc527505bda71354f9c8d91ca32 Mon Sep 17 00:00:00 2001 From: Coro Date: Tue, 11 Aug 2026 22:01:10 -0600 Subject: [PATCH] printf: avoid panic on %s/%c field width above u16::MAX write_padded padded with write!("{: padlen$}", "")?; + write_spaces(&mut writer, padlen)?; writer.write_all(text) } .map_err(FormatError::IoError) } +/// Write `n` space bytes directly to `writer`. +/// +/// Unlike `write!(writer, "{: std::io::Result<()> { + const SPACES: [u8; 64] = [b' '; 64]; + let mut remaining = n; + while remaining > 0 { + let chunk = remaining.min(SPACES.len()); + writer.write_all(&SPACES[..chunk])?; + remaining -= chunk; + } + Ok(()) +} + /// Check for a number ending with a '$' fn eat_argument_position(rest: &mut &[u8], index: &mut usize) -> Option { let original_index = *index; diff --git a/tests/by-util/test_printf.rs b/tests/by-util/test_printf.rs index 4ab67e128da..e1cd2becf3d 100644 --- a/tests/by-util/test_printf.rs +++ b/tests/by-util/test_printf.rs @@ -439,6 +439,19 @@ fn sub_min_width_negative() { .stdout_only("hello world "); } +#[test] +fn sub_string_char_width_above_u16_max_no_panic() { + // A %s/%c field width above u16::MAX must not panic (#12593, #12900). + new_ucmd!() + .args(&["%100000c", "A"]) + .succeeds() + .stdout_only(format!("{}A", " ".repeat(99999))); + new_ucmd!() + .args(&["%-100000s", "hi"]) + .succeeds() + .stdout_only(format!("hi{}", " ".repeat(99998))); +} + #[test] fn sub_str_max_chars_input() { new_ucmd!()