Skip to content

Commit

Permalink
Rollup merge of rust-lang#76662 - RalfJung:lib-test-miri, r=Mark-Simu…
Browse files Browse the repository at this point in the history
…lacrum

Fix liballoc test suite for Miri

Mostly, fix the regression introduced by rust-lang#75207 that caused slices (i.e., references) to be created to invalid memory or memory that has aliasing pointers that we want to keep valid. @dylni  this changes the type of `check_range` to only require the length, not the full reference to the slice, which indeed is all the information this function requires.

Also reduce the size of a test introduced in rust-lang#70793 to make it not take 3 minutes in Miri.

This makes https://github.com/RalfJung/miri-test-libstd work again.
  • Loading branch information
RalfJung authored Sep 13, 2020
2 parents 004800c + bb41740 commit e247c59
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 82 deletions.
6 changes: 1 addition & 5 deletions library/alloc/src/collections/vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1089,11 +1089,7 @@ impl<T> VecDeque<T> {
where
R: RangeBounds<usize>,
{
// SAFETY: This buffer is only used to check the range. It might be partially
// uninitialized, but `check_range` needs a contiguous slice.
// https://github.com/rust-lang/rust/pull/75207#discussion_r471193682
let buffer = unsafe { slice::from_raw_parts(self.ptr(), self.len()) };
let Range { start, end } = buffer.check_range(range);
let Range { start, end } = slice::check_range(self.len(), range);
let tail = self.wrap_add(self.tail, start);
let head = self.wrap_add(self.tail, end);
(tail, head)
Expand Down
2 changes: 2 additions & 0 deletions library/alloc/src/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ use crate::borrow::ToOwned;
use crate::boxed::Box;
use crate::vec::Vec;

#[unstable(feature = "slice_check_range", issue = "76393")]
pub use core::slice::check_range;
#[unstable(feature = "array_chunks", issue = "74985")]
pub use core::slice::ArrayChunks;
#[unstable(feature = "array_chunks", issue = "74985")]
Expand Down
3 changes: 2 additions & 1 deletion library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ use core::iter::{FromIterator, FusedIterator};
use core::ops::Bound::{Excluded, Included, Unbounded};
use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds};
use core::ptr;
use core::slice;
use core::str::{lossy, pattern::Pattern};

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

Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,7 @@ impl<T> Vec<T> {
// the hole, and the vector length is restored to the new length.
//
let len = self.len();
let Range { start, end } = self.check_range(range);
let Range { start, end } = slice::check_range(len, range);

unsafe {
// set self.vec length's to start, to be safe in case Drain is leaked
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/tests/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ fn test_from_iter_partially_drained_in_place_specialization() {
#[test]
fn test_from_iter_specialization_with_iterator_adapters() {
fn assert_in_place_trait<T: InPlaceIterable>(_: &T) {};
let src: Vec<usize> = vec![0usize; 65535];
let src: Vec<usize> = vec![0usize; 256];
let srcptr = src.as_ptr();
let iter = src
.into_iter()
Expand Down
148 changes: 74 additions & 74 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -354,79 +354,6 @@ impl<T> [T] {
unsafe { &mut *index.get_unchecked_mut(self) }
}

/// Converts a range over this slice to [`Range`].
///
/// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`].
///
/// [`get_unchecked`]: #method.get_unchecked
/// [`get_unchecked_mut`]: #method.get_unchecked_mut
///
/// # Panics
///
/// Panics if the range is out of bounds.
///
/// # Examples
///
/// ```
/// #![feature(slice_check_range)]
///
/// let v = [10, 40, 30];
/// assert_eq!(1..2, v.check_range(1..2));
/// assert_eq!(0..2, v.check_range(..2));
/// assert_eq!(1..3, v.check_range(1..));
/// ```
///
/// Panics when [`Index::index`] would panic:
///
/// ```should_panic
/// #![feature(slice_check_range)]
///
/// [10, 40, 30].check_range(2..1);
/// ```
///
/// ```should_panic
/// #![feature(slice_check_range)]
///
/// [10, 40, 30].check_range(1..4);
/// ```
///
/// ```should_panic
/// #![feature(slice_check_range)]
///
/// [10, 40, 30].check_range(1..=usize::MAX);
/// ```
///
/// [`Index::index`]: ops::Index::index
#[track_caller]
#[unstable(feature = "slice_check_range", issue = "76393")]
pub fn check_range<R: RangeBounds<usize>>(&self, range: R) -> Range<usize> {
let start = match range.start_bound() {
Bound::Included(&start) => start,
Bound::Excluded(start) => {
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
}
Bound::Unbounded => 0,
};

let len = self.len();
let end = match range.end_bound() {
Bound::Included(end) => {
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
}
Bound::Excluded(&end) => end,
Bound::Unbounded => len,
};

if start > end {
slice_index_order_fail(start, end);
}
if end > len {
slice_end_index_len_fail(end, len);
}

Range { start, end }
}

/// Returns a raw pointer to the slice's buffer.
///
/// The caller must ensure that the slice outlives the pointer this
Expand Down Expand Up @@ -2770,7 +2697,7 @@ impl<T> [T] {
where
T: Copy,
{
let Range { start: src_start, end: src_end } = self.check_range(src);
let Range { start: src_start, end: src_end } = check_range(self.len(), src);
let count = src_end - src_start;
assert!(dest <= self.len() - count, "dest is out of bounds");
// SAFETY: the conditions for `ptr::copy` have all been checked above,
Expand Down Expand Up @@ -6660,6 +6587,79 @@ unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> {
// Free functions
//

/// Performs bounds-checking of the given range.
/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`]
/// for slices of the given length.
///
/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked
/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut
///
/// # Panics
///
/// Panics if the range is out of bounds.
///
/// # Examples
///
/// ```
/// #![feature(slice_check_range)]
/// use std::slice;
///
/// let v = [10, 40, 30];
/// assert_eq!(1..2, slice::check_range(v.len(), 1..2));
/// assert_eq!(0..2, slice::check_range(v.len(), ..2));
/// assert_eq!(1..3, slice::check_range(v.len(), 1..));
/// ```
///
/// Panics when [`Index::index`] would panic:
///
/// ```should_panic
/// #![feature(slice_check_range)]
///
/// std::slice::check_range(3, 2..1);
/// ```
///
/// ```should_panic
/// #![feature(slice_check_range)]
///
/// std::slice::check_range(3, 1..4);
/// ```
///
/// ```should_panic
/// #![feature(slice_check_range)]
///
/// std::slice::check_range(3, 1..=usize::MAX);
/// ```
///
/// [`Index::index`]: ops::Index::index
#[track_caller]
#[unstable(feature = "slice_check_range", issue = "76393")]
pub fn check_range<R: RangeBounds<usize>>(len: usize, range: R) -> Range<usize> {
let start = match range.start_bound() {
Bound::Included(&start) => start,
Bound::Excluded(start) => {
start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
}
Bound::Unbounded => 0,
};

let end = match range.end_bound() {
Bound::Included(end) => {
end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
}
Bound::Excluded(&end) => end,
Bound::Unbounded => len,
};

if start > end {
slice_index_order_fail(start, end);
}
if end > len {
slice_end_index_len_fail(end, len);
}

Range { start, end }
}

/// Forms a slice from a pointer and a length.
///
/// The `len` argument is the number of **elements**, not the number of bytes.
Expand Down

0 comments on commit e247c59

Please sign in to comment.