printf: reject a * precision above INT_MAX for %s

The %s arm resolved a `*` precision without the check_precision call
the integer and float arms make, so a value above i32::MAX was used as
is instead of failing with "invalid precision". Check it there, for a
`*` precision only; a precision written in the format is still accepted.

Closes #15663
This commit is contained in:
fixfon authored and Dorian Péron committed 2026-10-28 00:26:46 +01:00
1 parent c21b7adc66
commit 3017dccfaf
2 files changed
+34

No files matched your search

@@ -369,7 +369,13 @@ impl Spec {
// For now, we let printf panic when we truncate within a code point.
// TODO: We need to not use Rust's formatting for aligning the output,
// so that we can just write bytes to stdout without panicking.
let star_precision = matches!(precision, Some(CanAsterisk::Asterisk(_)));
let precision = resolve_asterisk_precision(*precision, args);
// A `*` precision is an int argument, so it is capped at i32::MAX like
// the numeric specs; a precision written in the format is not.
if star_precision && let Some(precision) = precision {
check_precision(precision)?;
}
let os_str = args.next_string(*position);
let bytes = os_str_as_bytes(os_str)?;
+28
View File
@@ -666,6 +666,34 @@ fn invalid_precision_tests() {
}
}
#[test]
fn invalid_star_precision_string() {
for precision in ["2147483648", &i64::MAX.to_string()] {
new_ucmd!()
.args(&["%.*s|\n", precision, "x"])
.fails_with_code(1)
.no_stdout()
.stderr_is(format!("printf: invalid precision: '{precision}'\n"));
}
// The failure ends printf, so the rest of the format is not run.
new_ucmd!()
.args(&["%.*s %s\n", "2147483648", "a", "b"])
.fails_with_code(1)
.no_stdout()
.stderr_is("printf: invalid precision: '2147483648'\n");
// The cap is i32::MAX itself, and only a `*` precision is capped.
new_ucmd!()
.args(&["%.*s|\n", "2147483647", "x"])
.succeeds()
.stdout_only("x|\n");
new_ucmd!()
.args(&["%.4294967296s|\n", "x"])
.succeeds()
.stdout_only("x|\n");
}
// The following padding-tests test for the cases in which flags in ['0', ' '] are given.
// For integer, only try to pad when no precision is given, while
// for float, always try to pad