diff --git a/src/uu/stat/src/stat.rs b/src/uu/stat/src/stat.rs index 8e1f76779a1..2cc6c655701 100644 --- a/src/uu/stat/src/stat.rs +++ b/src/uu/stat/src/stat.rs @@ -405,11 +405,14 @@ fn determine_padding_char(flags: Flags) -> Padding { /// * `width` - The width of the field for the printed string. /// * `precision` - How many digits of precision, if any. fn print_str(s: &str, flags: Flags, width: usize, precision: Precision) { - let s = match precision { - Precision::Number(p) if p < s.len() => &s[..p], - _ => s, - }; - pad_and_print(s, flags.left, width, Padding::Space); + // Truncate and pad on the byte representation, so a precision that lands inside a multibyte character does not cause a panic. + let _ = write_padded_bytes( + std::io::stdout(), + s.as_bytes(), + flags.left, + width, + precision, + ); } /// Prints a `OsString` value based on the provided flags, width, and precision. diff --git a/tests/by-util/test_stat.rs b/tests/by-util/test_stat.rs index 153ef39c88d..13103ecc772 100644 --- a/tests/by-util/test_stat.rs +++ b/tests/by-util/test_stat.rs @@ -593,6 +593,17 @@ fn test_invalid_directive_after_multibyte_char() { } } +#[test] +fn test_precision_splits_multibyte_char_in_value() { + let ts = TestScenario::new(util_name!()); + let at = &ts.fixtures; + at.touch("é"); + ts.ucmd() + .args(&["-c", "%.1n", "é"]) + .succeeds() + .stdout_only_bytes([0xc3, b'\n']); +} + #[test] #[cfg(all( feature = "feat_selinux",