Skip to content

Commit 4cb4013

Browse files
committed
make Cell::swap panic if the Cells partially overlap
1 parent 3071e0a commit 4cb4013

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

library/core/src/cell.rs

+15-2
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@
237237

238238
use crate::cmp::Ordering;
239239
use crate::fmt::{self, Debug, Display};
240+
use crate::intrinsics::is_nonoverlapping;
240241
use crate::marker::{PhantomData, Unsize};
241242
use crate::mem;
242243
use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
@@ -415,6 +416,12 @@ impl<T> Cell<T> {
415416
/// Swaps the values of two `Cell`s.
416417
/// Difference with `std::mem::swap` is that this function doesn't require `&mut` reference.
417418
///
419+
/// # Panics
420+
///
421+
/// This function will panic if `self` and `other` are different `Cell`s that partially overlap.
422+
/// (Using just standard library methods, it is impossible to create such partially overlapping `Cell`s.
423+
/// However, unsafe code is allowed to e.g. create two `&Cell<[i32; 2]>` that partially overlap.)
424+
///
418425
/// # Examples
419426
///
420427
/// ```
@@ -430,14 +437,20 @@ impl<T> Cell<T> {
430437
#[stable(feature = "move_cell", since = "1.17.0")]
431438
pub fn swap(&self, other: &Self) {
432439
if ptr::eq(self, other) {
440+
// Swapping wouldn't change anything.
433441
return;
434442
}
443+
if !is_nonoverlapping(self, other, 1) {
444+
// See <https://github.com/rust-lang/rust/issues/80778> for why we need to stop here.
445+
panic!("`Cell::swap` on overlapping non-identical `Cell`s");
446+
}
435447
// SAFETY: This can be risky if called from separate threads, but `Cell`
436448
// is `!Sync` so this won't happen. This also won't invalidate any
437449
// pointers since `Cell` makes sure nothing else will be pointing into
438-
// either of these `Cell`s.
450+
// either of these `Cell`s. We also excluded shenanigans like partially overlapping `Cell`s,
451+
// so `swap` will just properly copy two full values of type `T` back and forth.
439452
unsafe {
440-
ptr::swap(self.value.get(), other.value.get());
453+
ptr::swap_nonoverlapping(self.value.get(), other.value.get(), 1);
441454
}
442455
}
443456

0 commit comments

Comments
 (0)