From 0944b78c050f013c5575cf8fa0bc7943b14b9358 Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Mon, 3 Aug 2026 11:27:50 +0000 Subject: [PATCH 1/2] automata: check for overflow in Span::offset Span is documented as unconstrained ("There are no constraints on the values of a span") and has public fields, but Span::offset performed unchecked additions: with debug assertions it panics with 'attempt to add with overflow', and in release builds it silently produces a wrapped, nonsensical span (e.g. 0..0 from a span at usize::MAX offset by 1). Use checked_add and document the panic, mirroring the equivalent fix in aho-corasick (BurntSushi/aho-corasick@0f3f5da). Found by running Kani's autoharness (model-checking/kani#3832) over regex-automata 0.4.16. Co-authored-by: Kiro --- regex-automata/src/util/search.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/regex-automata/src/util/search.rs b/regex-automata/src/util/search.rs index 37999f4bb..1a6b3c0af 100644 --- a/regex-automata/src/util/search.rs +++ b/regex-automata/src/util/search.rs @@ -843,9 +843,20 @@ impl Span { /// Returns a new span with `offset` added to this span's `start` and `end` /// values. + /// + /// # Panics + /// + /// This panics if adding `offset` to either part of this `Span` would + /// result in overflow. #[inline] pub fn offset(&self, offset: usize) -> Span { - Span { start: self.start + offset, end: self.end + offset } + Span { + start: self + .start + .checked_add(offset) + .expect("invalid start+offset"), + end: self.end.checked_add(offset).expect("invalid end+offset"), + } } } From e8b164b5df09cf70341d214adc253df77e8cbaba Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Wed, 5 Aug 2026 09:37:15 +0000 Subject: [PATCH 2/2] automata: overflow-specific panic messages and a regression test for Span::offset Review feedback: mention overflow and the method in the expect messages, and add a unit test pinning the overflow panic. Co-authored-by: Kiro --- regex-automata/src/util/search.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/regex-automata/src/util/search.rs b/regex-automata/src/util/search.rs index 1a6b3c0af..e882eb230 100644 --- a/regex-automata/src/util/search.rs +++ b/regex-automata/src/util/search.rs @@ -854,8 +854,11 @@ impl Span { start: self .start .checked_add(offset) - .expect("invalid start+offset"), - end: self.end.checked_add(offset).expect("invalid end+offset"), + .expect("Span::offset: start+offset overflowed usize"), + end: self + .end + .checked_add(offset) + .expect("Span::offset: end+offset overflowed usize"), } } } @@ -1951,6 +1954,15 @@ impl core::fmt::Display for MatchError { mod tests { use super::*; + #[test] + #[should_panic(expected = "overflowed usize")] + fn span_offset_overflow_panics() { + let s = Span { start: usize::MAX, end: usize::MAX }; + let _ = s.offset(1); + } + + use super::*; + // We test that our 'MatchError' type is the size we expect. This isn't an // API guarantee, but if the size increases, we really want to make sure we // decide to do that intentionally. So this should be a speed bump. And in