Skip to content

Commit ab63e68

Browse files
committed
bug: fix CaptureLocations::get to handle invalid offsets
The contract of this function says that any invalid group offset should result in a return value of None. In general, it worked fine, unless the offset was so big that some internal multiplication overflowed. That could in turn produce an incorrect result or a panic. So we fix that here with checked arithmetic. Fixes #738, Fixes #950
1 parent 4631799 commit ab63e68

File tree

3 files changed

+43
-1
lines changed

3 files changed

+43
-1
lines changed

src/re_bytes.rs

+21
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,27 @@ impl<'r> FusedIterator for CaptureNames<'r> {}
896896
/// In order to build a value of this type, you'll need to call the
897897
/// `capture_locations` method on the `Regex` being used to execute the search.
898898
/// The value returned can then be reused in subsequent searches.
899+
///
900+
/// # Example
901+
///
902+
/// This example shows how to create and use `CaptureLocations` in a search.
903+
///
904+
/// ```
905+
/// use regex::bytes::Regex;
906+
///
907+
/// let re = Regex::new(r"(?<first>\w+)\s+(?<last>\w+)").unwrap();
908+
/// let mut locs = re.capture_locations();
909+
/// let m = re.captures_read(&mut locs, b"Bruce Springsteen").unwrap();
910+
/// assert_eq!(0..17, m.range());
911+
/// assert_eq!(Some((0, 17)), locs.get(0));
912+
/// assert_eq!(Some((0, 5)), locs.get(1));
913+
/// assert_eq!(Some((6, 17)), locs.get(2));
914+
///
915+
/// // Asking for an invalid capture group always returns None.
916+
/// assert_eq!(None, locs.get(3));
917+
/// assert_eq!(None, locs.get(34973498648));
918+
/// assert_eq!(None, locs.get(9944060567225171988));
919+
/// ```
899920
#[derive(Clone, Debug)]
900921
pub struct CaptureLocations(re_trait::Locations);
901922

src/re_trait.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ impl Locations {
2020
/// not match anything. The positions returned are *always* byte indices
2121
/// with respect to the original string matched.
2222
pub fn pos(&self, i: usize) -> Option<(usize, usize)> {
23-
let (s, e) = (i * 2, i * 2 + 1);
23+
let (s, e) = (i.checked_mul(2)?, i.checked_mul(2)?.checked_add(1)?);
2424
match (self.0.get(s), self.0.get(e)) {
2525
(Some(&Some(s)), Some(&Some(e))) => Some((s, e)),
2626
_ => None,

src/re_unicode.rs

+21
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,27 @@ impl<'r, 't> FusedIterator for SplitN<'r, 't> {}
906906
/// In order to build a value of this type, you'll need to call the
907907
/// `capture_locations` method on the `Regex` being used to execute the search.
908908
/// The value returned can then be reused in subsequent searches.
909+
///
910+
/// # Example
911+
///
912+
/// This example shows how to create and use `CaptureLocations` in a search.
913+
///
914+
/// ```
915+
/// use regex::Regex;
916+
///
917+
/// let re = Regex::new(r"(?<first>\w+)\s+(?<last>\w+)").unwrap();
918+
/// let mut locs = re.capture_locations();
919+
/// let m = re.captures_read(&mut locs, "Bruce Springsteen").unwrap();
920+
/// assert_eq!(0..17, m.range());
921+
/// assert_eq!(Some((0, 17)), locs.get(0));
922+
/// assert_eq!(Some((0, 5)), locs.get(1));
923+
/// assert_eq!(Some((6, 17)), locs.get(2));
924+
///
925+
/// // Asking for an invalid capture group always returns None.
926+
/// assert_eq!(None, locs.get(3));
927+
/// assert_eq!(None, locs.get(34973498648));
928+
/// assert_eq!(None, locs.get(9944060567225171988));
929+
/// ```
909930
#[derive(Clone, Debug)]
910931
pub struct CaptureLocations(re_trait::Locations);
911932

0 commit comments

Comments
 (0)