Skip to content

Commit 78d5d37

Browse files
authored
Rollup merge of #42428 - scottmcm:str-get-overflow, r=sfackler
Add overflow checking for `str::get` with inclusive ranges Fixes #42401 Two commits here: 1. The first makes `str::index` just call `SliceIndex<str>::index`. It's intended to have no behavior change, except where the two methods were inconsistent. 2. The second actually adds the overflow checking to `get(_mut)` (and tests for it)
2 parents 02179bd + 808a08a commit 78d5d37

File tree

3 files changed

+73
-41
lines changed

3 files changed

+73
-41
lines changed

src/libcollections/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#![feature(repr_align)]
2525
#![feature(slice_rotate)]
2626
#![feature(splice)]
27+
#![feature(str_checked_slicing)]
2728
#![feature(str_escape)]
2829
#![feature(test)]
2930
#![feature(unboxed_closures)]

src/libcollections/tests/str.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,48 @@ fn test_slice_fail() {
358358
&"中华Việt Nam"[0..2];
359359
}
360360

361+
#[test]
362+
#[should_panic]
363+
fn test_str_slice_rangetoinclusive_max_panics() {
364+
&"hello"[...usize::max_value()];
365+
}
366+
367+
#[test]
368+
#[should_panic]
369+
fn test_str_slice_rangeinclusive_max_panics() {
370+
&"hello"[1...usize::max_value()];
371+
}
372+
373+
#[test]
374+
#[should_panic]
375+
fn test_str_slicemut_rangetoinclusive_max_panics() {
376+
let mut s = "hello".to_owned();
377+
let s: &mut str = &mut s;
378+
&mut s[...usize::max_value()];
379+
}
380+
381+
#[test]
382+
#[should_panic]
383+
fn test_str_slicemut_rangeinclusive_max_panics() {
384+
let mut s = "hello".to_owned();
385+
let s: &mut str = &mut s;
386+
&mut s[1...usize::max_value()];
387+
}
388+
389+
#[test]
390+
fn test_str_get_maxinclusive() {
391+
let mut s = "hello".to_owned();
392+
{
393+
let s: &str = &s;
394+
assert_eq!(s.get(...usize::max_value()), None);
395+
assert_eq!(s.get(1...usize::max_value()), None);
396+
}
397+
{
398+
let s: &mut str = &mut s;
399+
assert_eq!(s.get(...usize::max_value()), None);
400+
assert_eq!(s.get(1...usize::max_value()), None);
401+
}
402+
}
361403

362404
#[test]
363405
fn test_is_char_boundary() {

src/libcore/str/mod.rs

Lines changed: 30 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,12 +1617,7 @@ mod traits {
16171617

16181618
#[inline]
16191619
fn index(&self, index: ops::RangeTo<usize>) -> &str {
1620-
// is_char_boundary checks that the index is in [0, .len()]
1621-
if self.is_char_boundary(index.end) {
1622-
unsafe { self.slice_unchecked(0, index.end) }
1623-
} else {
1624-
super::slice_error_fail(self, 0, index.end)
1625-
}
1620+
index.index(self)
16261621
}
16271622
}
16281623

@@ -1636,12 +1631,7 @@ mod traits {
16361631
impl ops::IndexMut<ops::RangeTo<usize>> for str {
16371632
#[inline]
16381633
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
1639-
// is_char_boundary checks that the index is in [0, .len()]
1640-
if self.is_char_boundary(index.end) {
1641-
unsafe { self.slice_mut_unchecked(0, index.end) }
1642-
} else {
1643-
super::slice_error_fail(self, 0, index.end)
1644-
}
1634+
index.index_mut(self)
16451635
}
16461636
}
16471637

@@ -1657,12 +1647,7 @@ mod traits {
16571647

16581648
#[inline]
16591649
fn index(&self, index: ops::RangeFrom<usize>) -> &str {
1660-
// is_char_boundary checks that the index is in [0, .len()]
1661-
if self.is_char_boundary(index.start) {
1662-
unsafe { self.slice_unchecked(index.start, self.len()) }
1663-
} else {
1664-
super::slice_error_fail(self, index.start, self.len())
1665-
}
1650+
index.index(self)
16661651
}
16671652
}
16681653

@@ -1676,13 +1661,7 @@ mod traits {
16761661
impl ops::IndexMut<ops::RangeFrom<usize>> for str {
16771662
#[inline]
16781663
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
1679-
// is_char_boundary checks that the index is in [0, .len()]
1680-
if self.is_char_boundary(index.start) {
1681-
let len = self.len();
1682-
unsafe { self.slice_mut_unchecked(index.start, len) }
1683-
} else {
1684-
super::slice_error_fail(self, index.start, self.len())
1685-
}
1664+
index.index_mut(self)
16861665
}
16871666
}
16881667

@@ -1724,9 +1703,7 @@ mod traits {
17241703

17251704
#[inline]
17261705
fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
1727-
assert!(index.end != usize::max_value(),
1728-
"attempted to index str up to maximum usize");
1729-
self.index(index.start .. index.end+1)
1706+
index.index(self)
17301707
}
17311708
}
17321709

@@ -1738,9 +1715,7 @@ mod traits {
17381715

17391716
#[inline]
17401717
fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
1741-
assert!(index.end != usize::max_value(),
1742-
"attempted to index str up to maximum usize");
1743-
self.index(.. index.end+1)
1718+
index.index(self)
17441719
}
17451720
}
17461721

@@ -1750,9 +1725,7 @@ mod traits {
17501725
impl ops::IndexMut<ops::RangeInclusive<usize>> for str {
17511726
#[inline]
17521727
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
1753-
assert!(index.end != usize::max_value(),
1754-
"attempted to index str up to maximum usize");
1755-
self.index_mut(index.start .. index.end+1)
1728+
index.index_mut(self)
17561729
}
17571730
}
17581731
#[unstable(feature = "inclusive_range",
@@ -1761,9 +1734,7 @@ mod traits {
17611734
impl ops::IndexMut<ops::RangeToInclusive<usize>> for str {
17621735
#[inline]
17631736
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
1764-
assert!(index.end != usize::max_value(),
1765-
"attempted to index str up to maximum usize");
1766-
self.index_mut(.. index.end+1)
1737+
index.index_mut(self)
17671738
}
17681739
}
17691740

@@ -1886,6 +1857,7 @@ mod traits {
18861857
}
18871858
#[inline]
18881859
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
1860+
// is_char_boundary checks that the index is in [0, .len()]
18891861
if slice.is_char_boundary(self.end) {
18901862
unsafe { self.get_unchecked_mut(slice) }
18911863
} else {
@@ -1932,6 +1904,7 @@ mod traits {
19321904
}
19331905
#[inline]
19341906
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
1907+
// is_char_boundary checks that the index is in [0, .len()]
19351908
if slice.is_char_boundary(self.start) {
19361909
unsafe { self.get_unchecked_mut(slice) }
19371910
} else {
@@ -1945,11 +1918,19 @@ mod traits {
19451918
type Output = str;
19461919
#[inline]
19471920
fn get(self, slice: &str) -> Option<&Self::Output> {
1948-
(self.start..self.end+1).get(slice)
1921+
if let Some(end) = self.end.checked_add(1) {
1922+
(self.start..end).get(slice)
1923+
} else {
1924+
None
1925+
}
19491926
}
19501927
#[inline]
19511928
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
1952-
(self.start..self.end+1).get_mut(slice)
1929+
if let Some(end) = self.end.checked_add(1) {
1930+
(self.start..end).get_mut(slice)
1931+
} else {
1932+
None
1933+
}
19531934
}
19541935
#[inline]
19551936
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
@@ -1961,10 +1942,14 @@ mod traits {
19611942
}
19621943
#[inline]
19631944
fn index(self, slice: &str) -> &Self::Output {
1945+
assert!(self.end != usize::max_value(),
1946+
"attempted to index str up to maximum usize");
19641947
(self.start..self.end+1).index(slice)
19651948
}
19661949
#[inline]
19671950
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
1951+
assert!(self.end != usize::max_value(),
1952+
"attempted to index str up to maximum usize");
19681953
(self.start..self.end+1).index_mut(slice)
19691954
}
19701955
}
@@ -1976,15 +1961,15 @@ mod traits {
19761961
type Output = str;
19771962
#[inline]
19781963
fn get(self, slice: &str) -> Option<&Self::Output> {
1979-
if slice.is_char_boundary(self.end + 1) {
1964+
if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
19801965
Some(unsafe { self.get_unchecked(slice) })
19811966
} else {
19821967
None
19831968
}
19841969
}
19851970
#[inline]
19861971
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
1987-
if slice.is_char_boundary(self.end + 1) {
1972+
if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
19881973
Some(unsafe { self.get_unchecked_mut(slice) })
19891974
} else {
19901975
None
@@ -2002,11 +1987,15 @@ mod traits {
20021987
}
20031988
#[inline]
20041989
fn index(self, slice: &str) -> &Self::Output {
1990+
assert!(self.end != usize::max_value(),
1991+
"attempted to index str up to maximum usize");
20051992
let end = self.end + 1;
20061993
self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end))
20071994
}
20081995
#[inline]
20091996
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
1997+
assert!(self.end != usize::max_value(),
1998+
"attempted to index str up to maximum usize");
20101999
if slice.is_char_boundary(self.end) {
20112000
unsafe { self.get_unchecked_mut(slice) }
20122001
} else {

0 commit comments

Comments
 (0)