From 7b24ce692b780217ca15edd0bcfb1b5618bef171 Mon Sep 17 00:00:00 2001 From: Coro Date: Wed, 12 Aug 2026 20:40:42 -0600 Subject: [PATCH] find: reject a non-numeric prefix in the -size argument The -size argument was parsed with an un-anchored regex, so a value like "x5c" or "abc5c" silently matched the "5c" in the middle and was accepted as "5c". The extra sign group also accepted invalid double-sign forms such as "+-5c" and "--5c". Anchor the regex and allow only the one extra '+' that GNU accepts after the comparison sign, so "++5c" and "-+5c" stay valid while the junk-prefix and invalid-sign forms are rejected like GNU find. --- src/find/matchers/mod.rs | 41 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/find/matchers/mod.rs b/src/find/matchers/mod.rs index e35ebbbb..c4cef7d2 100644 --- a/src/find/matchers/mod.rs +++ b/src/find/matchers/mod.rs @@ -341,7 +341,11 @@ fn convert_arg_to_comparable_value_and_suffix( option_name: &str, value_as_string: &str, ) -> Result<(ComparableValue, String), Box> { - let re = Regex::new(r"([-+]?)[-+]?(\d+)(.*)$")?; + // Anchor at the start so a non-numeric prefix like "x5c" is rejected instead + // of silently parsing the "5c" in the middle. After the comparison sign GNU + // accepts one more optional '+' (so "++5c" and "-+5c" are valid, but "+-5c" + // and "--5c" are not), which `\+?` reproduces. + let re = Regex::new(r"^([-+]?)\+?(\d+)(.*)$")?; if let Some(groups) = re.captures(value_as_string) { if let Ok(val) = groups[2].parse::() { return Ok(( @@ -1815,6 +1819,41 @@ mod tests { ); } + #[test] + fn convert_arg_to_comparable_value_and_suffix_test() { + // Valid sign forms, matching GNU find's -size grammar. + assert_eq!( + convert_arg_to_comparable_value_and_suffix("-size", "5c").unwrap(), + (ComparableValue::EqualTo(5), "c".to_string()), + ); + assert_eq!( + convert_arg_to_comparable_value_and_suffix("-size", "+5c").unwrap(), + (ComparableValue::MoreThan(5), "c".to_string()), + ); + assert_eq!( + convert_arg_to_comparable_value_and_suffix("-size", "-5c").unwrap(), + (ComparableValue::LessThan(5), "c".to_string()), + ); + // GNU accepts one extra '+' after the comparison sign. + assert_eq!( + convert_arg_to_comparable_value_and_suffix("-size", "++5c").unwrap(), + (ComparableValue::MoreThan(5), "c".to_string()), + ); + assert_eq!( + convert_arg_to_comparable_value_and_suffix("-size", "-+5c").unwrap(), + (ComparableValue::LessThan(5), "c".to_string()), + ); + + // A non-numeric prefix ("x5c" used to be silently parsed as "5c") and the + // invalid double-sign forms are rejected, matching GNU. + for bad in ["x5c", "abc5c", "+-5c", "--5c", "+++5c"] { + assert!( + convert_arg_to_comparable_value_and_suffix("-size", bad).is_err(), + "expected `{bad}` to be rejected", + ); + } + } + #[test] fn convert_exception_arg_to_comparable_value_test() { let exception_args = ["1%2", "1%2%3", "1a2", "1%2a", "abc", "-", "+", "%"];