From 721a00a90024398dfc5cb3d1b0e65b1b1f54a222 Mon Sep 17 00:00:00 2001 From: Coro Date: Wed, 12 Aug 2026 20:30:53 -0600 Subject: [PATCH] numfmt: reject a leading '+' and scientific notation to match GNU GNU numfmt rejects a number with a leading '+' sign ("+5") as an invalid number, and rejects scientific notation ("1e-3") as an invalid suffix in input. Rust's i128 and f64 parsers accept both, so numfmt silently accepted them and printed a wrong value with exit 0. Reject them in parse_number_part, mirroring GNU's two distinct diagnostics. --- src/uu/numfmt/src/format.rs | 11 +++++++++++ tests/by-util/test_numfmt.rs | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/uu/numfmt/src/format.rs b/src/uu/numfmt/src/format.rs index 77febdaaa41..2c21d93f2fb 100644 --- a/src/uu/numfmt/src/format.rs +++ b/src/uu/numfmt/src/format.rs @@ -159,6 +159,17 @@ fn parse_number_part(s: &str, input: &str) -> Result { return Err(translate!("numfmt-error-invalid-number", "input" => input.quote())); } + // GNU numfmt does not accept a leading '+' sign nor scientific notation, but + // Rust's i128/f64 parsers do, so "+5" and "1e-3" would slip through. Reject + // them here, mirroring GNU's two distinct diagnostics (a leading sign is an + // "invalid number", an exponent is an "invalid suffix in input"). + if s.starts_with('+') { + return Err(translate!("numfmt-error-invalid-number", "input" => input.quote())); + } + if s.bytes().any(|b| b == b'e' || b == b'E') { + return Err(translate!("numfmt-error-invalid-suffix", "input" => input.quote())); + } + if let Ok(n) = s.parse::() { return Ok(ParsedNumber::ExactInt(n)); } diff --git a/tests/by-util/test_numfmt.rs b/tests/by-util/test_numfmt.rs index 33d810af269..2227dad61dc 100644 --- a/tests/by-util/test_numfmt.rs +++ b/tests/by-util/test_numfmt.rs @@ -185,6 +185,26 @@ fn test_header_error_if_negative() { .stderr_is("numfmt: invalid header value '-3'\n"); } +#[test] +fn test_reject_leading_plus_and_scientific_notation() { + // GNU numfmt rejects a leading '+' as an invalid number and rejects scientific + // notation as an invalid suffix; Rust's parsers accept both, so guard against it. + for input in ["+5", "+5K", "+1e-3"] { + new_ucmd!() + .arg("--from=auto") + .pipe_in(format!("{input}\n")) + .fails_with_code(2) + .stderr_is(format!("numfmt: invalid number: '{input}'\n")); + } + for input in ["1e-3", "1e+3", "5e-5", "1.0e-2", "-1e-5"] { + new_ucmd!() + .arg("--from=auto") + .pipe_in(format!("{input}\n")) + .fails_with_code(2) + .stderr_is(format!("numfmt: invalid suffix in input: '{input}'\n")); + } +} + #[test] fn test_negative() { new_ucmd!()