From 001966f3266118b7798bfdcd079adc0e9a31eeb0 Mon Sep 17 00:00:00 2001 From: weili <541602953@qq.com> Date: Tue, 9 Jun 2026 08:02:42 +0000 Subject: [PATCH] find: -name: don't panic on a malformed POSIX bracket class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A `-name` glob with a `[.`/`[=`/`[:` introducer whose closing delimiter is missing — only a lone `]` (or the delimiter) before a multibyte char, e.g. `'[[:]é'` — panicked (exit 101). `extract_bracket_expr` searched for *either* the delimiter or `]` and then added a blind `+ 2`, which overshot into the following character and sliced off a UTF-8 boundary. Search for the actual two-byte closing sequence `]` instead. A valid class (`[:alpha:]`) is unchanged; a malformed one returns None, so the caller treats `[` literally and accepts the pattern like GNU find (exit 0). Reachable via -name/-iname/-path/-ipath/-lname/-ilname. Adds a regression test. --- src/find/matchers/glob.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/find/matchers/glob.rs b/src/find/matchers/glob.rs index 1e1a73b..a0cbed7 100644 --- a/src/find/matchers/glob.rs +++ b/src/find/matchers/glob.rs @@ -83,7 +83,10 @@ fn extract_bracket_expr(pattern: &str) -> Option<(String, &str)> { if matches!(delim, '.' | '=' | ':') { let rest = chars.as_str(); - let end = rest.find([delim, ']'])? + 2; + // Search for the two-byte closer `]` (e.g. `:]`); + // matching either byte alone let `+ 2` overshoot a char boundary. + let closer = format!("{delim}]"); + let end = rest.find(closer.as_str())? + 2; expr.push_str(&rest[..end]); chars = rest[end..].chars(); } @@ -222,6 +225,16 @@ mod tests { assert_glob_regex(r"foo[bar[!baz", r"foo\[bar\[!baz"); } + #[test] + fn malformed_posix_class_with_multibyte_char() { + for pat in ["[[:]é", "[[:a]é", "[[.]é", "[[:é]", "[[=]😀"] { + assert!( + glob_to_regex(pat).is_some(), + "panicked or rejected: {pat:?}" + ); + } + } + #[test] fn incomplete_escape() { assert_eq!(glob_to_regex(r"foo\"), None);