Change:
The method is currently implemented as If called with , then it first creates a raw pointer to an element in the vector, and then it creates a mutable reference to that same element, asserting exclusive access. It then proceeds to use the original raw pointer even though we just asserted exclusive access through a different reference. In fact, when running the following program in miri: with , it fails with an error. <details<summaryClick to open miri failure</summary</detailsArguably it is also incorrect even when called with since creating the second raw pointer involves first creating a mutable reference to the entire slice, asserting exclusive access to the entire slice. However, miri does not fail in this case.
May this have something to do with the fact that slice indexing uses intrinsics?
No, it's because slice indexing uses the trait, which returns a mutable reference. So we create two mutable references to the same place, even if we immediately coerce them to a raw pointer. Unfortunately even would not help, because the indexing operaiton itself creates a mutable reference. So I think the only way would be to use , which feels a bit less fragile. cc
I'm pretty sure that slice indexing doesn't use but intrinsics. In fact is implemented with slice indexing, which would cause infinite recursion if slice indexing didn't use intrinsics. Now back at the issue, my point wasn't that the previous borrow isn't invalidated because slice indexing use intrinsics, but that Miri doesn't catch it because it gets confused by the intrinsics.
Oh right... well... it's still not intrinsics, it's weird builtin magic, which I know is not really helping the discussion. Aaaanyway: Your insight was the important one I needed: We can actually fix this by changing the to , no other changes needed. The builtin magic will then never create a mutable reference, but directly create a raw pointer to the destination(s).
Good catch! Hm... is still a reference though, so this still relies on indexing being primitive. But yes, this should work and fix the Miri failure. Well, the idea is that with the primitive operations, no reference to the entire slice is created so the previous borrow is not invalidated -- so Miri is behaving as intended here. But indeed this difference between primitive and non-primitive indexing can be confusing.
Could it be rewritten using to avoid the issue?
Ah, nice, you can do it without unsafe code. I feel like I should have thought of this, considering that I wrote .
Note that has an additional check for when the two s alias, while doesn't. While this shouldn't produce an observable behaviour, it is a bit inconsistent and may slightly impact performance
Assigning as discussed as part of the and removing .
I did not know about (or I had forgotten about it)... this is very interesting, and it makes some rather strong assumption: it assumes that two of the same type will either start at the same address or be disjoint. They may never "partially overlap". That does preclude some other possibly sound APIs... But anyway, that is just a tangent. EDIT: oops I should not write such comments when I am sleep-deprived, this makes no sense.^^ calls , not , so all is good.
Actually, existence of pretty much means that overlapping s of the same type where cannot exist in safe Rust. Consider the following code: This will cause double-free due to swapping two overlapping pointers. I don't think it's necessarily a bad thing myself, is useful, and I'm not seeing why somebody would want to have overlapping cells.
works fine for overlapping regions. Your code is unsafe, so I don't see how this could possibly demonstrate a soundness problem. You could write the same code without just using . EDIT: Actually, you did use . So what does this even have to do with ?
In short, if did allow getting two cells of the same type that is then swapping them could cause UB. In this example I'm using to create two overlapping regions and then swap them using . (yeah, there is a lot of noise due to , but it boils down to creating two cells whose values overlap) Of course, having an API that creates two overlapped types is unlikely to be very practical, so this is likely not a practical issue. This issue I don't think exists with types as doesn't exist for types, so for instance providing implementation for that returns would be safe.
That's what I was trying to get at, but concluded is not possible. To demonstrate this, you need to use only safe code, except for an API that arguably also should be sound, like for example: Can you cause UB using only safe code and (or some similar, well-encapsulated bit of unsafe code)?
! I now see what you mean by double-free. Good catch!
The (hypothetical) conversion from to would also be unsound since it would allow to create overlapping subarrays.
good point, one can use the slice-to-array methods that already exist. This issue is about though, sorry for derailing it -- I'll open a new one for .
Opened
FWIW, in case this can also be viewed as an instance of However, for I cannot really see a way that this code could be legal.
This PR fixes the problem:

Discussion:
#![feature(auto_traits)] #![feature(or_patterns)] #![feature(prelude_import)] <ins> #![feature(raw_ref_macros)] </ins> #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] #![feature(simd_ffi)]

#[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn swap(&mut self, a: usize, b: usize) { <del> // Can't take two mutable loans from one vector, so instead just cast // them to their raw pointers to do the swap. let pa: *mut T = &mut self[a]; let pb: *mut T = &mut self[b]; </del> <ins> // Can't take two mutable loans from one vector, so instead use raw pointers. let pa = ptr::raw_mut!(self[a]); let pb = ptr::raw_mut!(self[b]); </ins> // SAFETY: `pa` and `pb` have been created from safe mutable references and refer // to elements in the slice and therefore are guaranteed to be valid and aligned. // Note that accessing the elements behind `a` and `b` is checked and will