Skip to content

Commit bb41740

Browse files
committed
fix slice::check_range aliasing problems
1 parent f75d29f commit bb41740

File tree

6 files changed

+81
-82
lines changed

6 files changed

+81
-82
lines changed

library/alloc/src/collections/vec_deque.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -1089,11 +1089,7 @@ impl<T> VecDeque<T> {
10891089
where
10901090
R: RangeBounds<usize>,
10911091
{
1092-
// SAFETY: This buffer is only used to check the range. It might be partially
1093-
// uninitialized, but `check_range` needs a contiguous slice.
1094-
// https://github.com/rust-lang/rust/pull/75207#discussion_r471193682
1095-
let buffer = unsafe { slice::from_raw_parts(self.ptr(), self.len()) };
1096-
let Range { start, end } = buffer.check_range(range);
1092+
let Range { start, end } = slice::check_range(self.len(), range);
10971093
let tail = self.wrap_add(self.tail, start);
10981094
let head = self.wrap_add(self.tail, end);
10991095
(tail, head)

library/alloc/src/slice.rs

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ use crate::borrow::ToOwned;
9191
use crate::boxed::Box;
9292
use crate::vec::Vec;
9393

94+
#[unstable(feature = "slice_check_range", issue = "76393")]
95+
pub use core::slice::check_range;
9496
#[unstable(feature = "array_chunks", issue = "74985")]
9597
pub use core::slice::ArrayChunks;
9698
#[unstable(feature = "array_chunks", issue = "74985")]

library/alloc/src/string.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator};
4949
use core::ops::Bound::{Excluded, Included, Unbounded};
5050
use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
5151
use core::ptr;
52+
use core::slice;
5253
use core::str::{lossy, pattern::Pattern};
5354

5455
use crate::borrow::{Cow, ToOwned};
@@ -1506,7 +1507,7 @@ impl String {
15061507
// of the vector version. The data is just plain bytes.
15071508
// Because the range removal happens in Drop, if the Drain iterator is leaked,
15081509
// the removal will not happen.
1509-
let Range { start, end } = self.as_bytes().check_range(range);
1510+
let Range { start, end } = slice::check_range(self.len(), range);
15101511
assert!(self.is_char_boundary(start));
15111512
assert!(self.is_char_boundary(end));
15121513

library/alloc/src/vec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1310,7 +1310,7 @@ impl<T> Vec<T> {
13101310
// the hole, and the vector length is restored to the new length.
13111311
//
13121312
let len = self.len();
1313-
let Range { start, end } = self.check_range(range);
1313+
let Range { start, end } = slice::check_range(len, range);
13141314

13151315
unsafe {
13161316
// set self.vec length's to start, to be safe in case Drain is leaked

library/alloc/tests/vec.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -880,7 +880,7 @@ fn test_from_iter_partially_drained_in_place_specialization() {
880880
#[test]
881881
fn test_from_iter_specialization_with_iterator_adapters() {
882882
fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {};
883-
let src: Vec<usize> = vec![0usize; if cfg!(miri) { 256 } else { 65535 }];
883+
let src: Vec<usize> = vec![0usize; 256];
884884
let srcptr = src.as_ptr();
885885
let iter = src
886886
.into_iter()

library/core/src/slice/mod.rs

+74-74
Original file line numberDiff line numberDiff line change
@@ -354,79 +354,6 @@ impl<T> [T] {
354354
unsafe { &mut *index.get_unchecked_mut(self) }
355355
}
356356

357-
/// Converts a range over this slice to [`Range`].
358-
///
359-
/// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`].
360-
///
361-
/// [`get_unchecked`]: #method.get_unchecked
362-
/// [`get_unchecked_mut`]: #method.get_unchecked_mut
363-
///
364-
/// # Panics
365-
///
366-
/// Panics if the range is out of bounds.
367-
///
368-
/// # Examples
369-
///
370-
/// ```
371-
/// #![feature(slice_check_range)]
372-
///
373-
/// let v = [10, 40, 30];
374-
/// assert_eq!(1..2, v.check_range(1..2));
375-
/// assert_eq!(0..2, v.check_range(..2));
376-
/// assert_eq!(1..3, v.check_range(1..));
377-
/// ```
378-
///
379-
/// Panics when [`Index::index`] would panic:
380-
///
381-
/// ```should_panic
382-
/// #![feature(slice_check_range)]
383-
///
384-
/// [10, 40, 30].check_range(2..1);
385-
/// ```
386-
///
387-
/// ```should_panic
388-
/// #![feature(slice_check_range)]
389-
///
390-
/// [10, 40, 30].check_range(1..4);
391-
/// ```
392-
///
393-
/// ```should_panic
394-
/// #![feature(slice_check_range)]
395-
///
396-
/// [10, 40, 30].check_range(1..=usize::MAX);
397-
/// ```
398-
///
399-
/// [`Index::index`]: ops::Index::index
400-
#[track_caller]
401-
#[unstable(feature = "slice_check_range", issue = "76393")]
402-
pub fn check_range<R: RangeBounds<usize>>(&self, range: R) -> Range<usize> {
403-
let start = match range.start_bound() {
404-
Bound::Included(&start) => start,
405-
Bound::Excluded(start) => {
406-
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
407-
}
408-
Bound::Unbounded => 0,
409-
};
410-
411-
let len = self.len();
412-
let end = match range.end_bound() {
413-
Bound::Included(end) => {
414-
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
415-
}
416-
Bound::Excluded(&end) => end,
417-
Bound::Unbounded => len,
418-
};
419-
420-
if start > end {
421-
slice_index_order_fail(start, end);
422-
}
423-
if end > len {
424-
slice_end_index_len_fail(end, len);
425-
}
426-
427-
Range { start, end }
428-
}
429-
430357
/// Returns a raw pointer to the slice's buffer.
431358
///
432359
/// The caller must ensure that the slice outlives the pointer this
@@ -2770,7 +2697,7 @@ impl<T> [T] {
27702697
where
27712698
T: Copy,
27722699
{
2773-
let Range { start: src_start, end: src_end } = self.check_range(src);
2700+
let Range { start: src_start, end: src_end } = check_range(self.len(), src);
27742701
let count = src_end - src_start;
27752702
assert!(dest <= self.len() - count, "dest is out of bounds");
27762703
// SAFETY: the conditions for `ptr::copy` have all been checked above,
@@ -6660,6 +6587,79 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
66606587
// Free functions
66616588
//
66626589

6590+
/// Performs bounds-checking of the given range.
6591+
/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`]
6592+
/// for slices of the given length.
6593+
///
6594+
/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
6595+
/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
6596+
///
6597+
/// # Panics
6598+
///
6599+
/// Panics if the range is out of bounds.
6600+
///
6601+
/// # Examples
6602+
///
6603+
/// ```
6604+
/// #![feature(slice_check_range)]
6605+
/// use std::slice;
6606+
///
6607+
/// let v = [10, 40, 30];
6608+
/// assert_eq!(1..2, slice::check_range(v.len(), 1..2));
6609+
/// assert_eq!(0..2, slice::check_range(v.len(), ..2));
6610+
/// assert_eq!(1..3, slice::check_range(v.len(), 1..));
6611+
/// ```
6612+
///
6613+
/// Panics when [`Index::index`] would panic:
6614+
///
6615+
/// ```should_panic
6616+
/// #![feature(slice_check_range)]
6617+
///
6618+
/// std::slice::check_range(3, 2..1);
6619+
/// ```
6620+
///
6621+
/// ```should_panic
6622+
/// #![feature(slice_check_range)]
6623+
///
6624+
/// std::slice::check_range(3, 1..4);
6625+
/// ```
6626+
///
6627+
/// ```should_panic
6628+
/// #![feature(slice_check_range)]
6629+
///
6630+
/// std::slice::check_range(3, 1..=usize::MAX);
6631+
/// ```
6632+
///
6633+
/// [`Index::index`]: ops::Index::index
6634+
#[track_caller]
6635+
#[unstable(feature = "slice_check_range", issue = "76393")]
6636+
pub fn check_range<R: RangeBounds<usize>>(len: usize, range: R) -> Range<usize> {
6637+
let start = match range.start_bound() {
6638+
Bound::Included(&start) => start,
6639+
Bound::Excluded(start) => {
6640+
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
6641+
}
6642+
Bound::Unbounded => 0,
6643+
};
6644+
6645+
let end = match range.end_bound() {
6646+
Bound::Included(end) => {
6647+
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
6648+
}
6649+
Bound::Excluded(&end) => end,
6650+
Bound::Unbounded => len,
6651+
};
6652+
6653+
if start > end {
6654+
slice_index_order_fail(start, end);
6655+
}
6656+
if end > len {
6657+
slice_end_index_len_fail(end, len);
6658+
}
6659+
6660+
Range { start, end }
6661+
}
6662+
66636663
/// Forms a slice from a pointer and a length.
66646664
///
66656665
/// The `len` argument is the number of **elements**, not the number of bytes.

0 commit comments

Comments
 (0)