Rollup merge of #42428 - scottmcm:str-get-overflow, r=sfackler
Add overflow checking for `str::get` with inclusive ranges Fixes https://github.com/rust-lang/rust/issues/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)
This commit is contained in:
commit
78d5d37235
@ -24,6 +24,7 @@
|
|||||||
#![feature(repr_align)]
|
#![feature(repr_align)]
|
||||||
#![feature(slice_rotate)]
|
#![feature(slice_rotate)]
|
||||||
#![feature(splice)]
|
#![feature(splice)]
|
||||||
|
#![feature(str_checked_slicing)]
|
||||||
#![feature(str_escape)]
|
#![feature(str_escape)]
|
||||||
#![feature(test)]
|
#![feature(test)]
|
||||||
#![feature(unboxed_closures)]
|
#![feature(unboxed_closures)]
|
||||||
|
@ -358,6 +358,48 @@ fn test_slice_fail() {
|
|||||||
&"中华Việt Nam"[0..2];
|
&"中华Việt Nam"[0..2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_str_slice_rangetoinclusive_max_panics() {
|
||||||
|
&"hello"[...usize::max_value()];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_str_slice_rangeinclusive_max_panics() {
|
||||||
|
&"hello"[1...usize::max_value()];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_str_slicemut_rangetoinclusive_max_panics() {
|
||||||
|
let mut s = "hello".to_owned();
|
||||||
|
let s: &mut str = &mut s;
|
||||||
|
&mut s[...usize::max_value()];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[should_panic]
|
||||||
|
fn test_str_slicemut_rangeinclusive_max_panics() {
|
||||||
|
let mut s = "hello".to_owned();
|
||||||
|
let s: &mut str = &mut s;
|
||||||
|
&mut s[1...usize::max_value()];
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_str_get_maxinclusive() {
|
||||||
|
let mut s = "hello".to_owned();
|
||||||
|
{
|
||||||
|
let s: &str = &s;
|
||||||
|
assert_eq!(s.get(...usize::max_value()), None);
|
||||||
|
assert_eq!(s.get(1...usize::max_value()), None);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let s: &mut str = &mut s;
|
||||||
|
assert_eq!(s.get(...usize::max_value()), None);
|
||||||
|
assert_eq!(s.get(1...usize::max_value()), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_is_char_boundary() {
|
fn test_is_char_boundary() {
|
||||||
|
@ -1617,12 +1617,7 @@ mod traits {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: ops::RangeTo<usize>) -> &str {
|
fn index(&self, index: ops::RangeTo<usize>) -> &str {
|
||||||
// is_char_boundary checks that the index is in [0, .len()]
|
index.index(self)
|
||||||
if self.is_char_boundary(index.end) {
|
|
||||||
unsafe { self.slice_unchecked(0, index.end) }
|
|
||||||
} else {
|
|
||||||
super::slice_error_fail(self, 0, index.end)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1636,12 +1631,7 @@ mod traits {
|
|||||||
impl ops::IndexMut<ops::RangeTo<usize>> for str {
|
impl ops::IndexMut<ops::RangeTo<usize>> for str {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
|
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
|
||||||
// is_char_boundary checks that the index is in [0, .len()]
|
index.index_mut(self)
|
||||||
if self.is_char_boundary(index.end) {
|
|
||||||
unsafe { self.slice_mut_unchecked(0, index.end) }
|
|
||||||
} else {
|
|
||||||
super::slice_error_fail(self, 0, index.end)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1657,12 +1647,7 @@ mod traits {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: ops::RangeFrom<usize>) -> &str {
|
fn index(&self, index: ops::RangeFrom<usize>) -> &str {
|
||||||
// is_char_boundary checks that the index is in [0, .len()]
|
index.index(self)
|
||||||
if self.is_char_boundary(index.start) {
|
|
||||||
unsafe { self.slice_unchecked(index.start, self.len()) }
|
|
||||||
} else {
|
|
||||||
super::slice_error_fail(self, index.start, self.len())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1676,13 +1661,7 @@ mod traits {
|
|||||||
impl ops::IndexMut<ops::RangeFrom<usize>> for str {
|
impl ops::IndexMut<ops::RangeFrom<usize>> for str {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
|
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
|
||||||
// is_char_boundary checks that the index is in [0, .len()]
|
index.index_mut(self)
|
||||||
if self.is_char_boundary(index.start) {
|
|
||||||
let len = self.len();
|
|
||||||
unsafe { self.slice_mut_unchecked(index.start, len) }
|
|
||||||
} else {
|
|
||||||
super::slice_error_fail(self, index.start, self.len())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1724,9 +1703,7 @@ mod traits {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
|
fn index(&self, index: ops::RangeInclusive<usize>) -> &str {
|
||||||
assert!(index.end != usize::max_value(),
|
index.index(self)
|
||||||
"attempted to index str up to maximum usize");
|
|
||||||
self.index(index.start .. index.end+1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1738,9 +1715,7 @@ mod traits {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
|
fn index(&self, index: ops::RangeToInclusive<usize>) -> &str {
|
||||||
assert!(index.end != usize::max_value(),
|
index.index(self)
|
||||||
"attempted to index str up to maximum usize");
|
|
||||||
self.index(.. index.end+1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1750,9 +1725,7 @@ mod traits {
|
|||||||
impl ops::IndexMut<ops::RangeInclusive<usize>> for str {
|
impl ops::IndexMut<ops::RangeInclusive<usize>> for str {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
|
fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut str {
|
||||||
assert!(index.end != usize::max_value(),
|
index.index_mut(self)
|
||||||
"attempted to index str up to maximum usize");
|
|
||||||
self.index_mut(index.start .. index.end+1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[unstable(feature = "inclusive_range",
|
#[unstable(feature = "inclusive_range",
|
||||||
@ -1761,9 +1734,7 @@ mod traits {
|
|||||||
impl ops::IndexMut<ops::RangeToInclusive<usize>> for str {
|
impl ops::IndexMut<ops::RangeToInclusive<usize>> for str {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
|
fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut str {
|
||||||
assert!(index.end != usize::max_value(),
|
index.index_mut(self)
|
||||||
"attempted to index str up to maximum usize");
|
|
||||||
self.index_mut(.. index.end+1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1886,6 +1857,7 @@ mod traits {
|
|||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
||||||
|
// is_char_boundary checks that the index is in [0, .len()]
|
||||||
if slice.is_char_boundary(self.end) {
|
if slice.is_char_boundary(self.end) {
|
||||||
unsafe { self.get_unchecked_mut(slice) }
|
unsafe { self.get_unchecked_mut(slice) }
|
||||||
} else {
|
} else {
|
||||||
@ -1932,6 +1904,7 @@ mod traits {
|
|||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
||||||
|
// is_char_boundary checks that the index is in [0, .len()]
|
||||||
if slice.is_char_boundary(self.start) {
|
if slice.is_char_boundary(self.start) {
|
||||||
unsafe { self.get_unchecked_mut(slice) }
|
unsafe { self.get_unchecked_mut(slice) }
|
||||||
} else {
|
} else {
|
||||||
@ -1945,11 +1918,19 @@ mod traits {
|
|||||||
type Output = str;
|
type Output = str;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||||
(self.start..self.end+1).get(slice)
|
if let Some(end) = self.end.checked_add(1) {
|
||||||
|
(self.start..end).get(slice)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
|
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
|
||||||
(self.start..self.end+1).get_mut(slice)
|
if let Some(end) = self.end.checked_add(1) {
|
||||||
|
(self.start..end).get_mut(slice)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
|
unsafe fn get_unchecked(self, slice: &str) -> &Self::Output {
|
||||||
@ -1961,10 +1942,14 @@ mod traits {
|
|||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(self, slice: &str) -> &Self::Output {
|
fn index(self, slice: &str) -> &Self::Output {
|
||||||
|
assert!(self.end != usize::max_value(),
|
||||||
|
"attempted to index str up to maximum usize");
|
||||||
(self.start..self.end+1).index(slice)
|
(self.start..self.end+1).index(slice)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
||||||
|
assert!(self.end != usize::max_value(),
|
||||||
|
"attempted to index str up to maximum usize");
|
||||||
(self.start..self.end+1).index_mut(slice)
|
(self.start..self.end+1).index_mut(slice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1976,7 +1961,7 @@ mod traits {
|
|||||||
type Output = str;
|
type Output = str;
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get(self, slice: &str) -> Option<&Self::Output> {
|
fn get(self, slice: &str) -> Option<&Self::Output> {
|
||||||
if slice.is_char_boundary(self.end + 1) {
|
if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
|
||||||
Some(unsafe { self.get_unchecked(slice) })
|
Some(unsafe { self.get_unchecked(slice) })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -1984,7 +1969,7 @@ mod traits {
|
|||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
|
fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> {
|
||||||
if slice.is_char_boundary(self.end + 1) {
|
if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) {
|
||||||
Some(unsafe { self.get_unchecked_mut(slice) })
|
Some(unsafe { self.get_unchecked_mut(slice) })
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -2002,11 +1987,15 @@ mod traits {
|
|||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(self, slice: &str) -> &Self::Output {
|
fn index(self, slice: &str) -> &Self::Output {
|
||||||
|
assert!(self.end != usize::max_value(),
|
||||||
|
"attempted to index str up to maximum usize");
|
||||||
let end = self.end + 1;
|
let end = self.end + 1;
|
||||||
self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end))
|
self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end))
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
|
||||||
|
assert!(self.end != usize::max_value(),
|
||||||
|
"attempted to index str up to maximum usize");
|
||||||
if slice.is_char_boundary(self.end) {
|
if slice.is_char_boundary(self.end) {
|
||||||
unsafe { self.get_unchecked_mut(slice) }
|
unsafe { self.get_unchecked_mut(slice) }
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user