Change:
To my knowledge, the following code is intended to be legal: However, Miri currently flags this as UB. I believe this is , but for . Discovered while writing . cc
Yeah this looks pretty similar. uses under the hood though, so I wonder why the issue still exists here. Looks like is implemented via -- and indeed, this errors, too:
The problem is in this line: The here is a slice method, so this creates a slice covering the entire , which overlaps with the mutable reference created before and thus invalidates it.
It shouldn't be too hard to locally fix this, but that duplicates some code and there are some other uses of in . Ideally, this would all use raw slices to avoid making any uniqueness promises. But without , raw slices are not very useful.
Here's a possible fix:
Fix PR is up:

Discussion:
} #[test] <del> fn test_stable_push_pop() { </del> <ins> fn test_stable_pointers() { /// Pull an element from the iterator, then drop it. /// Useful to cover both the `next` and `drop` paths of an iterator. fn next_then_drop<I: Iterator>(mut i: I) { i.next().unwrap(); drop(i); } </ins> // Test that, if we reserved enough space, adding and removing elements does not // invalidate references into the vector (such as `v0`).  This test also // runs in Miri, which would detect such problems. <del> let mut v = Vec::with_capacity(10); </del> <ins> let mut v = Vec::with_capacity(128); </ins> v.push(13); <del> // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. let v0 = unsafe { &*(&v[0] as *const _) }; </del> <ins> // Laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. let v0 = &mut v[0]; let v0 = unsafe { &mut *(v0 as *mut _) }; </ins> // Now do a bunch of things and occasionally use `v0` again to assert it is still valid. <ins> // Pushing/inserting and popping/removing </ins> v.push(1); v.push(2); v.insert(1, 1);

v.remove(1); v.pop().unwrap(); assert_eq!(*v0, 13); <ins> v.push(1); v.swap_remove(1); assert_eq!(v.len(), 2); v.swap_remove(1); // swap_remove the last element assert_eq!(*v0, 13); // Appending v.append(&mut vec![27, 19]); assert_eq!(*v0, 13); // Extending v.extend_from_slice(&[1, 2]); v.extend(&[1, 2]); // `slice::Iter` (with `T: Copy`) specialization v.extend(vec![2, 3]); // `vec::IntoIter` specialization v.extend(std::iter::once(3)); // `TrustedLen` specialization v.extend(std::iter::empty::<i32>()); // `TrustedLen` specialization with empty iterator v.extend(std::iter::once(3).filter(|_| true)); // base case v.extend(std::iter::once(&3)); // `cloned` specialization assert_eq!(*v0, 13); // Truncation v.truncate(2); assert_eq!(*v0, 13); // Resizing v.resize_with(v.len() + 10, || 42); assert_eq!(*v0, 13); v.resize_with(2, || panic!()); assert_eq!(*v0, 13); // No-op reservation v.reserve(32); v.reserve_exact(32); assert_eq!(*v0, 13); // Partial draining v.resize_with(10, || 42); next_then_drop(v.drain(5..)); assert_eq!(*v0, 13); // Splicing v.resize_with(10, || 42); next_then_drop(v.splice(5.., vec![1, 2, 3, 4, 5])); // empty tail after range assert_eq!(*v0, 13); next_then_drop(v.splice(5..8, vec![1])); // replacement is smaller than original range assert_eq!(*v0, 13); next_then_drop(v.splice(5..6, vec![1; 10].into_iter().filter(|_| true))); // lower bound not exact assert_eq!(*v0, 13); // Smoke test that would fire even outside Miri if an actual relocation happened. *v0 -= 13; assert_eq!(v[0], 0); </ins> } // https://github.com/rust-lang/rust/pull/49496 introduced specialization based on:

if len > self.len { return; } <del> let s = self.get_unchecked_mut(len..) as *mut _; </del> <ins> let remaining_len = self.len - len; let s = slice::from_raw_parts_mut(self.as_mut_ptr().add(len), remaining_len); </ins> self.len = len; ptr::drop_in_place(s); }

#[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { <ins> let len = self.len(); assert!(index < len); </ins> unsafe { // We replace self[index] with the last element. Note that if the <del> // bounds check on hole succeeds there must be a last element (which </del> <ins> // bounds check above succeeds there must be a last element (which </ins> // can be self[index] itself). <del> let hole: *mut T = &mut self[index]; let last = ptr::read(self.get_unchecked(self.len - 1)); self.len -= 1; </del> <ins> let last = ptr::read(self.as_ptr().add(len - 1)); let hole: *mut T = self.as_mut_ptr().add(index); self.set_len(len - 1); </ins> ptr::replace(hole, last) } }

} else { unsafe { self.len -= 1; <del> Some(ptr::read(self.get_unchecked(self.len()))) </del> <ins> Some(ptr::read(self.as_ptr().add(self.len()))) </ins> } } }

let (lower, _) = iterator.size_hint(); let mut vector = Vec::with_capacity(lower.saturating_add(1)); unsafe { <del> ptr::write(vector.get_unchecked_mut(0), element); </del> <ins> ptr::write(vector.as_mut_ptr(), element); </ins> vector.set_len(1); } vector

self.reserve(slice.len()); unsafe { let len = self.len(); <ins> let dst_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(len), slice.len()); dst_slice.copy_from_slice(slice); </ins> self.set_len(len + slice.len()); <del> self.get_unchecked_mut(len..).copy_from_slice(slice); </del> } } }

self.reserve(lower.saturating_add(1)); } unsafe { <del> ptr::write(self.get_unchecked_mut(len), element); </del> <ins> ptr::write(self.as_mut_ptr().add(len), element); </ins> // NB can't overflow since we would have had to alloc the address space self.set_len(len + 1); }