Skip to content

Commit 913db6e

Browse files
authored
fix(glob): restore bracket cache on '*' backtrack (#2167)
Backtracking from `*` left `no_more_bracket_closes` stale, so valid bracket expressions were treated as literals and produced false-positive matches. Snapshot the bracket-cache flag at the star restore point and restore it on backtrack.
1 parent 7213166 commit 913db6e

1 file changed

Lines changed: 10 additions & 0 deletions

File tree

  • crates/bashkit/src/interpreter

crates/bashkit/src/interpreter/glob.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ impl Interpreter {
197197
// never needed again), keeping the worst case O(value.len * pattern.len).
198198
let mut star_pat: Option<std::iter::Peekable<std::str::Chars>> = None;
199199
let mut star_val: Option<std::iter::Peekable<std::str::Chars>> = None;
200+
let mut star_no_more_bracket_closes = false;
200201

201202
// On a content mismatch, resume from the most recent `*`, letting it
202203
// consume one more value char. With no active `*`, the match fails.
@@ -207,6 +208,7 @@ impl Interpreter {
207208
sv.next();
208209
pattern_chars = sp.clone();
209210
value_chars = sv.clone();
211+
no_more_bracket_closes = star_no_more_bracket_closes;
210212
continue;
211213
}
212214
}
@@ -262,6 +264,7 @@ impl Interpreter {
262264
// value char and retries. Overwrites any earlier `*`.
263265
star_pat = Some(pattern_chars.clone());
264266
star_val = Some(value_chars.clone());
267+
star_no_more_bracket_closes = no_more_bracket_closes;
265268
}
266269
(Some('?'), _) => {
267270
// Check for extglob ?(...)
@@ -982,6 +985,13 @@ mod tests {
982985
assert!(interp.pattern_matches("a", "[a]"));
983986
}
984987

988+
#[test]
989+
fn star_backtracking_restores_bracket_cache_state() {
990+
let interp = interp();
991+
992+
assert!(!interp.pattern_matches("azX[a]z[", "*[a]z["));
993+
}
994+
985995
// THREAT[TM-DOS-031]: a run of `*` must not cause exponential backtracking.
986996
// Before the linear restore-point rewrite, patterns like `****…%=` (found
987997
// by `glob_fuzz`) or `*a*a*…b` blew up to a libFuzzer timeout. These cases

0 commit comments

Comments
 (0)