Skip to content

Commit e926ddc

Browse files
committed
Fix panic in BoundedBacktracker when haystack length exceeds capacity
Issue #1344: When a regex like /^.{0,404600}$/ causes the bounded backtracker's max_haystack_len() to return 0, the meta layer's guard in wrappers.rs used '>' instead of '>=', allowing the engine to be selected for an empty string (length 0). The engine then panicked with MatchError(HaystackTooLong { len: 0 }) from an unwrap(). The fix changes the guard from '>' to '>=' so that when max_haystack_len() is 0, no haystack (including the empty string) is excluded from the backtracker engine. Added regression test max_haystack_len_zero_excludes_engine.
1 parent 72d650c commit e926ddc

2 files changed

Lines changed: 31 additions & 2 deletions

File tree

‎regex-automata/src/meta/wrappers.rs‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,11 @@ impl BoundedBacktracker {
176176
return None;
177177
}
178178
// If the backtracker is just going to return an error because the
179-
// haystack is too long, then obviously do not use it.
180-
if input.get_span().len() > engine.max_haystack_len() {
179+
// haystack is too long, then obviously do not use it. Note that
180+
// we use '>=' here because when max_haystack_len() returns 0,
181+
// the backtracker cannot handle any haystack (including the empty
182+
// string with length 0).
183+
if input.get_span().len() >= engine.max_haystack_len() {
181184
return None;
182185
}
183186
Some(engine)

‎regex-automata/src/nfa/thompson/backtrack.rs‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,4 +1905,30 @@ mod tests {
19051905
.unwrap();
19061906
assert_eq!(0, re.max_haystack_len());
19071907
}
1908+
1909+
// Regression test for https://github.com/rust-lang/regex/issues/1344
1910+
// When the bounded backtracker's max_haystack_len() returns 0 (because
1911+
// the NFA has more states than the visited capacity can support), the
1912+
// meta layer's BoundedBacktrackerEngine guard must properly exclude the
1913+
// engine so it doesn't try to match and panic with HaystackTooLong.
1914+
#[cfg(feature = "syntax")]
1915+
#[test]
1916+
fn max_haystack_len_zero_excludes_engine() {
1917+
// Build a BoundedBacktracker whose max_haystack_len is 0.
1918+
let re = BoundedBacktracker::builder()
1919+
.configure(BoundedBacktracker::config().visited_capacity(10))
1920+
.build(r"[0-9A-Za-z]{100}")
1921+
.unwrap();
1922+
assert_eq!(0, re.max_haystack_len());
1923+
1924+
// The meta layer's guard at line 180 in wrappers.rs should use
1925+
// '>=' (not '>') to correctly exclude the engine when max_haystack_len
1926+
// is 0. This test verifies the guard condition directly.
1927+
let span_len = 0; // empty haystack
1928+
let max = re.max_haystack_len();
1929+
assert!(
1930+
span_len >= max,
1931+
"empty string must be excluded when max_haystack_len is 0"
1932+
);
1933+
}
19081934
}

0 commit comments

Comments
 (0)