diff options
| author | bors <bors@rust-lang.org> | 2018-12-13 07:12:19 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-12-13 07:12:19 +0000 |
| commit | 9fe5cb5342244a716055fa0162e795deabd4985c (patch) | |
| tree | f2a928470eca9ca49926eb634de4dee78d0a2189 | |
| parent | ced7cc5c6523ff478599ed9188df37e91fd96c68 (diff) | |
| parent | feb775c834361f635df9e3824f9d2ae9582becbb (diff) | |
| download | rust-9fe5cb5342244a716055fa0162e795deabd4985c.tar.gz rust-9fe5cb5342244a716055fa0162e795deabd4985c.zip | |
Auto merge of #56161 - RalfJung:vecdeque-stacked-borrows, r=SimonSapin
VecDeque: fix for stacked borrows `VecDeque` violates a version of stacked borrows where creating a shared reference is not enough to make a location *mutably accessible* from raw pointers (and I think that is the version we want). There are two problems: * Creating a `NonNull<T>` from `&mut T` goes through `&T` (inferred for a `_`), then `*const T`, then `NonNull<T>`. That means in this stricter version of Stacked Borrows, we cannot actually write to such a `NonNull` because it was created from a shared reference! This PR fixes that by going from `&mut T` to `*mut T` to `*const T`. * `VecDeque::drain` creates the `Drain` struct by *first* creating a `NonNull` from `self` (which is an `&mut VecDeque`), and *then* calling `self.buffer_as_mut_slice()`. The latter reborrows `self`, asserting that `self` is currently the unique pointer to access this `VecDeque`, and hence invalidating the `NonNull` that was created earlier. This PR fixes that by instead using `self.buffer_as_slice()`, which only performs read accesses and creates only shared references, meaning the raw pointer (`NonNull`) remains valid. It is possible that other methods on `VecDeque` do something similar, miri's test coverage of `VecDeque` is sparse to say the least. Cc @nikomatsakis @Gankro
| -rw-r--r-- | src/liballoc/collections/vec_deque.rs | 5 | ||||
| -rw-r--r-- | src/libcore/ptr.rs | 8 |
2 files changed, 8 insertions, 5 deletions
diff --git a/src/liballoc/collections/vec_deque.rs b/src/liballoc/collections/vec_deque.rs index c0adeca4eb5..0c5926fbaf1 100644 --- a/src/liballoc/collections/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -1026,7 +1026,10 @@ impl<T> VecDeque<T> { iter: Iter { tail: drain_tail, head: drain_head, - ring: unsafe { self.buffer_as_mut_slice() }, + // Crucially, we only create shared references from `self` here and read from + // it. We do not write to `self` nor reborrow to a mutable reference. + // Hence the raw pointer we created above, for `deque`, remains valid. + ring: unsafe { self.buffer_as_slice() }, }, } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index b11ae303272..f61e582f764 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -2848,14 +2848,14 @@ impl<T: ?Sized> fmt::Pointer for Unique<T> { #[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From<&'a mut T> for Unique<T> { fn from(reference: &'a mut T) -> Self { - Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData } + Unique { pointer: unsafe { NonZero(reference as *mut T) }, _marker: PhantomData } } } #[unstable(feature = "ptr_internals", issue = "0")] impl<'a, T: ?Sized> From<&'a T> for Unique<T> { fn from(reference: &'a T) -> Self { - Unique { pointer: unsafe { NonZero(reference as _) }, _marker: PhantomData } + Unique { pointer: unsafe { NonZero(reference as *const T) }, _marker: PhantomData } } } @@ -3058,7 +3058,7 @@ impl<T: ?Sized> From<Unique<T>> for NonNull<T> { impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> { #[inline] fn from(reference: &'a mut T) -> Self { - NonNull { pointer: unsafe { NonZero(reference as _) } } + NonNull { pointer: unsafe { NonZero(reference as *mut T) } } } } @@ -3066,6 +3066,6 @@ impl<'a, T: ?Sized> From<&'a mut T> for NonNull<T> { impl<'a, T: ?Sized> From<&'a T> for NonNull<T> { #[inline] fn from(reference: &'a T) -> Self { - NonNull { pointer: unsafe { NonZero(reference as _) } } + NonNull { pointer: unsafe { NonZero(reference as *const T) } } } } |
