Skip to content

Commit c528d24

Browse files
committed
fix slice::check_range aliasing problems
1 parent d888725 commit c528d24

File tree

7 files changed

+85
-86
lines changed

7 files changed

+85
-86
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
@@ -894,7 +894,7 @@ fn test_from_iter_partially_drained_in_place_specialization() {
894894
#[test]
895895
fn test_from_iter_specialization_with_iterator_adapters() {
896896
fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {};
897-
let src: Vec<usize> = vec![0usize; if cfg!(miri) { 256 } else { 65535 }];
897+
let src: Vec<usize> = vec![0usize; 256];
898898
let srcptr = src.as_ptr();
899899
let iter = src
900900
.into_iter()

library/core/src/slice/index.rs

+74-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Indexing implementations for `[T]`.
22
3-
use crate::ops;
3+
use crate::ops::{self, Bound, Range, RangeBounds};
44
use crate::ptr;
55

66
#[stable(feature = "rust1", since = "1.0.0")]
@@ -62,6 +62,79 @@ pub(super) fn slice_end_index_overflow_fail() -> ! {
6262
panic!("attempted to index slice up to maximum usize");
6363
}
6464

65+
/// Performs bounds-checking of the given range.
66+
/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`]
67+
/// for slices of the given length.
68+
///
69+
/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
70+
/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
71+
///
72+
/// # Panics
73+
///
74+
/// Panics if the range is out of bounds.
75+
///
76+
/// # Examples
77+
///
78+
/// ```
79+
/// #![feature(slice_check_range)]
80+
/// use std::slice;
81+
///
82+
/// let v = [10, 40, 30];
83+
/// assert_eq!(1..2, slice::check_range(v.len(), 1..2));
84+
/// assert_eq!(0..2, slice::check_range(v.len(), ..2));
85+
/// assert_eq!(1..3, slice::check_range(v.len(), 1..));
86+
/// ```
87+
///
88+
/// Panics when [`Index::index`] would panic:
89+
///
90+
/// ```should_panic
91+
/// #![feature(slice_check_range)]
92+
///
93+
/// std::slice::check_range(3, 2..1);
94+
/// ```
95+
///
96+
/// ```should_panic
97+
/// #![feature(slice_check_range)]
98+
///
99+
/// std::slice::check_range(3, 1..4);
100+
/// ```
101+
///
102+
/// ```should_panic
103+
/// #![feature(slice_check_range)]
104+
///
105+
/// std::slice::check_range(3, 1..=usize::MAX);
106+
/// ```
107+
///
108+
/// [`Index::index`]: crate::ops::Index::index
109+
#[track_caller]
110+
#[unstable(feature = "slice_check_range", issue = "76393")]
111+
pub fn check_range<R: RangeBounds<usize>>(len: usize, range: R) -> Range<usize> {
112+
let start = match range.start_bound() {
113+
Bound::Included(&start) => start,
114+
Bound::Excluded(start) => {
115+
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
116+
}
117+
Bound::Unbounded => 0,
118+
};
119+
120+
let end = match range.end_bound() {
121+
Bound::Included(end) => {
122+
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
123+
}
124+
Bound::Excluded(&end) => end,
125+
Bound::Unbounded => len,
126+
};
127+
128+
if start > end {
129+
slice_index_order_fail(start, end);
130+
}
131+
if end > len {
132+
slice_end_index_len_fail(end, len);
133+
}
134+
135+
Range { start, end }
136+
}
137+
65138
mod private_slice_index {
66139
use super::ops;
67140
#[stable(feature = "slice_get_slice", since = "1.28.0")]

library/core/src/slice/mod.rs

+4-77
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less};
1212
use crate::intrinsics::assume;
1313
use crate::marker::{self, Copy};
1414
use crate::mem;
15-
use crate::ops::{Bound, FnMut, Range, RangeBounds};
15+
use crate::ops::{FnMut, Range, RangeBounds};
1616
use crate::option::Option;
1717
use crate::option::Option::{None, Some};
1818
use crate::ptr::{self, NonNull};
@@ -72,8 +72,8 @@ pub use sort::heapsort;
7272
#[stable(feature = "slice_get_slice", since = "1.28.0")]
7373
pub use index::SliceIndex;
7474

75-
use index::{slice_end_index_len_fail, slice_index_order_fail};
76-
use index::{slice_end_index_overflow_fail, slice_start_index_overflow_fail};
75+
#[unstable(feature = "slice_check_range", issue = "76393")]
76+
pub use index::check_range;
7777

7878
#[lang = "slice"]
7979
#[cfg(not(test))]
@@ -378,79 +378,6 @@ impl<T> [T] {
378378
unsafe { &mut *index.get_unchecked_mut(self) }
379379
}
380380

381-
/// Converts a range over this slice to [`Range`].
382-
///
383-
/// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`].
384-
///
385-
/// [`get_unchecked`]: #method.get_unchecked
386-
/// [`get_unchecked_mut`]: #method.get_unchecked_mut
387-
///
388-
/// # Panics
389-
///
390-
/// Panics if the range is out of bounds.
391-
///
392-
/// # Examples
393-
///
394-
/// ```
395-
/// #![feature(slice_check_range)]
396-
///
397-
/// let v = [10, 40, 30];
398-
/// assert_eq!(1..2, v.check_range(1..2));
399-
/// assert_eq!(0..2, v.check_range(..2));
400-
/// assert_eq!(1..3, v.check_range(1..));
401-
/// ```
402-
///
403-
/// Panics when [`Index::index`] would panic:
404-
///
405-
/// ```should_panic
406-
/// #![feature(slice_check_range)]
407-
///
408-
/// [10, 40, 30].check_range(2..1);
409-
/// ```
410-
///
411-
/// ```should_panic
412-
/// #![feature(slice_check_range)]
413-
///
414-
/// [10, 40, 30].check_range(1..4);
415-
/// ```
416-
///
417-
/// ```should_panic
418-
/// #![feature(slice_check_range)]
419-
///
420-
/// [10, 40, 30].check_range(1..=usize::MAX);
421-
/// ```
422-
///
423-
/// [`Index::index`]: crate::ops::Index::index
424-
#[track_caller]
425-
#[unstable(feature = "slice_check_range", issue = "76393")]
426-
pub fn check_range<R: RangeBounds<usize>>(&self, range: R) -> Range<usize> {
427-
let start = match range.start_bound() {
428-
Bound::Included(&start) => start,
429-
Bound::Excluded(start) => {
430-
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
431-
}
432-
Bound::Unbounded => 0,
433-
};
434-
435-
let len = self.len();
436-
let end = match range.end_bound() {
437-
Bound::Included(end) => {
438-
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
439-
}
440-
Bound::Excluded(&end) => end,
441-
Bound::Unbounded => len,
442-
};
443-
444-
if start > end {
445-
slice_index_order_fail(start, end);
446-
}
447-
if end > len {
448-
slice_end_index_len_fail(end, len);
449-
}
450-
451-
Range { start, end }
452-
}
453-
454381
/// Returns a raw pointer to the slice's buffer.
455382
///
456383
/// The caller must ensure that the slice outlives the pointer this
@@ -2794,7 +2721,7 @@ impl<T> [T] {
27942721
where
27952722
T: Copy,
27962723
{
2797-
let Range { start: src_start, end: src_end } = self.check_range(src);
2724+
let Range { start: src_start, end: src_end } = check_range(self.len(), src);
27982725
let count = src_end - src_start;
27992726
assert!(dest <= self.len() - count, "dest is out of bounds");
28002727
// SAFETY: the conditions for `ptr::copy` have all been checked above,

0 commit comments

Comments
 (0)