Change:
In , it was uncovered that is making some rather strong assumptions: two s with different address but the same type must not overlap. Not only is this a scarily non-local safety invariant, it is also fundamentally incomaptible with some APIs that ought to be correct, as demonstrated by this snippet (thanks to and for help with working out the example): to see the issue: will duplicate parts of the memory range when there is overlap, which leads to double-drop (other parts of the memory range are just lost, leading to memory leaks, but that is not the main issue here). This is not itself a soundness issue as it requires unsafe code to trigger UB. But this likely reflects an unintended consequence of . This got stabilized in as part of That commit references and an RFC, but is not mentioned in either of them. was in Accept that is unsound and document "non-overlap" as part of the safety invariant. This seems very fragile. Make not misbehave on overlap, either by panicking or by only swapping the non-overlapping parts. Cc
was in , which was authored by a "Charlie Fan". This is probably
Cc
This makes the method sound, but it seems like there could be other seems-like-they-should-be-ok cell projections that break under this behavior.
I don't think so. This makes the function behave "strangely", but since no data is duplicated nor discarded, I think it is sound.
I share this hunch, although the code, out of nowhere, may look very contrived. Consider: So it seems like -king (at least for non- types) is the only option that would allow us too keep the structural property of s, which, imho, is a very intuitive programmer mindset (and thus, a mistake that many would do should they not know about this caveat), and so a quite important thing to preserve .
That is an example of the "strange" behavior not being the right thing for this code, but it is not an unsoundness of per se. Your unsafe code is simply making wrong assumptions about the functional behavior of . Current favors the first operand in case of overlap (according to documentation); unsafe code that incorrectly assumes it would favor the second operand would be equally wrong. I don't see a bug in either way. IMO it seems rather strange to only panic for non- types. Btw, also exists. does not have array/slice projection functions though and they would be wrong due to the counts, so overlapping probably truly are not a thing.
At the very least, an argument that aren't allowed to overlap is easier to defend than that aren't allowed to overlap. Plus also, doesn't have guaranteed layout in the first place, so any example using tuples is (currently) implementation-detail-tied even before hitting . You could still construct an example using only types, of course; just replace the tuple with an actual type. You could even make it . As I understand it, there's three main cases here. ping two nonoverlapping is fine. ping two partially overlapping without any bound on has a sound, if surprising, definition, where the nonoverlapping part of the arrays are swapped. ping two partially overlapping unknown is unsound in any definition, unless both has no safety invariants and the overlapping portion is . The third case is obviously the most restricting one, and is defined on . To expound on first of the two subissues: Consider a type with the extra safety invariant that the second must be double the first . could even be . It would be valid to create two from , as you'd have and . There is no possible definition of (other than a no-op) which preserves the safety invariant. And of course the impl doesn't even know about the safety invariant. I could probably create an even worse example using underaligned types and relying on a specific endianness, perhaps even accidentally breaking validity invariants (think around partially overlapping ). The only two resolutions I'm confident in are making always panic for overlapping cells (because there could be safety invariants being broken) or forbidding overlapping s to -compatible types (optionally: that would be broken by ). And I don't like the subtle implications of the latter (e.g. being unsound for unbound ).
I don't think would be immediately unsound, you would still need a way to create overlapping s.
In particular, they certainly can only overlap in restricted ways -- if they overlap such that one's sits on the other's , I can already cause UB without just by storing into that and then reading it as a . Oh I see... to only swap the non-overlapping parts we have to make an argument that these parts have the same type (safety+validity invariant). Which... seems utterly bogus now that I think about it. Worse, the invariant could correlate the overlapping with the non-overlapping part, as in your example. (Removed a whole bunch of nonsense where I try to find some special cases that work.) Yeah we should make it panic.^^ It is unsound to create an to these though, even without I can already violate the safety invariant here by setting the second reference to . Ergo this is not a problem for , we can already assume such references do not exist. I am confused, is there a negation missing somewhere in this sentence?
Fair. I'm fairly confident that it'd be possible to come up with some safety invariant that a partial swap would break, though, with more data-dependent qualities. The parenthetical is an optional relaxation of the potential requirement (but at the cost of a lot of complexity).
But shouldn't it be forbidding overlapping s to -incompatible types? Not that I know what either of these things mean, but forbidding incompatible seems to make more sense than forbidding compatible.^^
Yeah, poor verbage. I meant roughly "forbidding overlapping s of types that can be used in (i.e. sized types)", with the optional extension of "only for those actually broken by " (however that would be defined).
that partially overlapping s through an enum is problematic even without :
Enums isn't really the same thing. That enum projections are unsound , but as also discussed in that article, struct projections are typically ok, and the array projection discussed here is essentially a struct projection, not an enum projection.
I would like to bring up my crate  which allows projecting through using a macro. example usage: Note: doesn't allow projecting through enums for exactly the reasons that explained. I'm not sure how could interact with to produce bad behavior, because you can only project to fields, which can't be swapped with their parent, but just in case someone else finds something interesting. i.e. This isn't possible, so it's not possible to project through to a field that's the same type as the parent. Alongside the fact that all fields are disjoint means that cell-project should only produce overlapping if they are also .
I agree with here. Sum types and product types are different, and really should commute around product types, i.e., ought to be sound.
You can use , which led me to this issue (it'd be good if we could support field projection inside of and ).
While you could use to check that the tuple layout conforms to the C-like layout needed to do such projection, I don't see how your specific use of would lead to two partially overlapping though. Note that the problem is not with projecting to a single field, but to a group/subset containing multiple fields (or like in the array/slice example, to a subarray/subslice with length ).
Oh I see, you're right. False alarm.

Discussion:
use crate::cmp::Ordering; use crate::fmt::{self, Debug, Display}; <ins> use crate::intrinsics::is_nonoverlapping; </ins> use crate::marker::{PhantomData, Unsize}; use crate::mem; use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};

/// Swaps the values of two `Cell`s. /// Difference with `std::mem::swap` is that this function doesn't require `&mut` reference. /// <ins> /// # Panics /// /// This function will panic if `self` and `other` are different `Cell`s that partially overlap. /// (Using just standard library methods, it is impossible to create such partially overlapping `Cell`s. /// However, unsafe code is allowed to e.g. create two `&Cell<[i32; 2]>` that partially overlap.) /// </ins> /// # Examples /// /// ```

#[stable(feature = "move_cell", since = "1.17.0")] pub fn swap(&self, other: &Self) { if ptr::eq(self, other) { <ins> // Swapping wouldn't change anything. </ins> return; } <ins> if !is_nonoverlapping(self, other, 1) { // See <https://github.com/rust-lang/rust/issues/80778> for why we need to stop here. panic!("`Cell::swap` on overlapping non-identical `Cell`s"); } </ins> // SAFETY: This can be risky if called from separate threads, but `Cell` // is `!Sync` so this won't happen. This also won't invalidate any // pointers since `Cell` makes sure nothing else will be pointing into <del> // either of these `Cell`s. </del> <ins> // either of these `Cell`s. We also excluded shenanigans like partially overlapping `Cell`s, // so `swap` will just properly copy two full values of type `T` back and forth. </ins> unsafe { <del> ptr::swap(self.value.get(), other.value.get()); </del> <ins> mem::swap(&mut *self.value.get(), &mut *other.value.get()); </ins> } }

let size = mem::size_of::<T>() .checked_mul(count) .expect("is_nonoverlapping: `size_of::<T>() * count` overflows a usize"); <del> let diff = if src_usize > dst_usize { src_usize - dst_usize } else { dst_usize - src_usize }; </del> <ins> let diff = src_usize.abs_diff(dst_usize); </ins> // If the absolute distance between the ptrs is at least as big as the size of the buffer, // they do not overlap. diff >= size