Skip to content

Commit e6b6b27

Browse files
Kev1n8cakebaker
andauthored
printf: Check precision before writing into stdout (#6511)
* Add a new error type InvalidPrecision * check if the precision is valid before writing to stdout when it is signedInt, unsigned, or float * add tests for invalid precision check * add tests for invalid precision check * fix possible cross-platform issue that code failing to pass on some tests * uucore/format: inline var in format string --------- Co-authored-by: Daniel Hofstetter <[email protected]>
1 parent ff38949 commit e6b6b27

File tree

3 files changed

+32
-0
lines changed

3 files changed

+32
-0
lines changed

src/uucore/src/lib/features/format/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ pub enum FormatError {
6262
TooManySpecs(Vec<u8>),
6363
NeedAtLeastOneSpec(Vec<u8>),
6464
WrongSpecType,
65+
InvalidPrecision(String),
6566
}
6667

6768
impl Error for FormatError {}
@@ -91,6 +92,7 @@ impl Display for FormatError {
9192
"format '{}' has no % directive",
9293
String::from_utf8_lossy(s)
9394
),
95+
Self::InvalidPrecision(precision) => write!(f, "invalid precision: '{precision}'"),
9496
// TODO: Error message below needs some work
9597
Self::WrongSpecType => write!(f, "wrong % directive type was given"),
9698
Self::IoError(_) => write!(f, "io error"),

src/uucore/src/lib/features/format/spec.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,10 @@ impl Spec {
374374
let precision = resolve_asterisk(*precision, &mut args)?.unwrap_or(0);
375375
let i = args.get_i64();
376376

377+
if precision as u64 > i32::MAX as u64 {
378+
return Err(FormatError::InvalidPrecision(precision.to_string()));
379+
}
380+
377381
num_format::SignedInt {
378382
width,
379383
precision,
@@ -393,6 +397,10 @@ impl Spec {
393397
let precision = resolve_asterisk(*precision, &mut args)?.unwrap_or(0);
394398
let i = args.get_u64();
395399

400+
if precision as u64 > i32::MAX as u64 {
401+
return Err(FormatError::InvalidPrecision(precision.to_string()));
402+
}
403+
396404
num_format::UnsignedInt {
397405
variant: *variant,
398406
precision,
@@ -415,6 +423,10 @@ impl Spec {
415423
let precision = resolve_asterisk(*precision, &mut args)?.unwrap_or(6);
416424
let f = args.get_f64();
417425

426+
if precision as u64 > i32::MAX as u64 {
427+
return Err(FormatError::InvalidPrecision(precision.to_string()));
428+
}
429+
418430
num_format::Float {
419431
width,
420432
precision,

tests/by-util/test_printf.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,3 +774,21 @@ fn format_spec_zero_string_fails() {
774774
// It is invalid to have the format spec '%0s'
775775
new_ucmd!().args(&["%0s", "3"]).fails().code_is(1);
776776
}
777+
778+
#[test]
779+
fn invalid_precision_fails() {
780+
// It is invalid to have length of output string greater than i32::MAX
781+
new_ucmd!()
782+
.args(&["%.*d", "2147483648", "0"])
783+
.fails()
784+
.stderr_is("printf: invalid precision: '2147483648'\n");
785+
}
786+
787+
#[test]
788+
fn float_invalid_precision_fails() {
789+
// It is invalid to have length of output string greater than i32::MAX
790+
new_ucmd!()
791+
.args(&["%.*f", "2147483648", "0"])
792+
.fails()
793+
.stderr_is("printf: invalid precision: '2147483648'\n");
794+
}

0 commit comments

Comments
 (0)