diff --git a/regex-automata/src/dfa/onepass.rs b/regex-automata/src/dfa/onepass.rs
index 85f820ef54..a56a462511 100644
--- a/regex-automata/src/dfa/onepass.rs
+++ b/regex-automata/src/dfa/onepass.rs
@@ -2215,11 +2215,16 @@ impl DFA {
// We *also* need to set any explicit slots that are active as part of
// the path to the match state.
if self.explicit_slot_start < slots.len() {
- // NOTE: The 'cache.explicit_slots()' slice is setup at the
- // beginning of every search such that it is guaranteed to return a
- // slice of length equivalent to 'slots[explicit_slot_start..]'.
- slots[self.explicit_slot_start..]
- .copy_from_slice(cache.explicit_slots());
+ // Copy only the slots that exist in the cache. When a regex has
+ // capture groups with zero repetition (e.g., (abc){0}), the cache
+ // may have fewer explicit slots than what the caller provided.
+ let cache_slots = cache.explicit_slots();
+ let available = core::cmp::min(
+ cache_slots.len(),
+ slots.len().saturating_sub(self.explicit_slot_start),
+ );
+ slots[self.explicit_slot_start..self.explicit_slot_start + available]
+ .copy_from_slice(&cache_slots[..available]);
epsilons.slots().apply(at, &mut slots[self.explicit_slot_start..]);
}
*matched_pid = Some(pid);
@@ -2577,7 +2582,7 @@ impl Cache {
}
fn setup_search(&mut self, explicit_slot_len: usize) {
- self.explicit_slot_len = explicit_slot_len;
+ self.explicit_slot_len = core::cmp::min(explicit_slot_len, self.explicit_slots.len());
}
}
diff --git a/regex-automata/tests/dfa/onepass/mod.rs b/regex-automata/tests/dfa/onepass/mod.rs
index 9d6ab475ef..aa656435d4 100644
--- a/regex-automata/tests/dfa/onepass/mod.rs
+++ b/regex-automata/tests/dfa/onepass/mod.rs
@@ -1,2 +1,3 @@
#[cfg(not(miri))]
mod suite;
+mod regression;
diff --git a/regex-automata/tests/dfa/onepass/regression.rs b/regex-automata/tests/dfa/onepass/regression.rs
new file mode 100644
index 0000000000..1968e26ea8
--- /dev/null
+++ b/regex-automata/tests/dfa/onepass/regression.rs
@@ -0,0 +1,51 @@
+// Regression test for zero-repetition capture groups causing panic.
+// See: https://github.com/rust-lang/regex/issues/XXX
+#[test]
+fn zero_repetition_capture_group() {
+ use regex_automata::{
+ dfa::onepass::DFA,
+ util::primitives::NonMaxUsize,
+ Anchored, Input,
+ };
+
+ let expr = DFA::new(r"(abc)(ABC){0}").unwrap();
+ let s = "abcABC";
+ let input = Input::new(s).span(0..s.len()).anchored(Anchored::Yes);
+
+ // Test with slot array sized for the pattern
+ let mut cache = expr.create_cache();
+ let mut slots: Vec