about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2023-08-14 09:48:13 +0200
committerRalf Jung <post@ralfj.de>2023-08-14 09:49:33 +0200
commit4cb4013464b3ec594e42dbed4d80110ee1817988 (patch)
treeb95f517eae4d4d8282973912eb227f93dad4a71d
parent3071e0aef6dfd0a150c3fb1da0abad4ec86ca0aa (diff)
downloadrust-4cb4013464b3ec594e42dbed4d80110ee1817988.tar.gz
rust-4cb4013464b3ec594e42dbed4d80110ee1817988.zip
make Cell::swap panic if the Cells partially overlap
-rw-r--r--library/core/src/cell.rs17
1 files changed, 15 insertions, 2 deletions
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index bf4c682d33e..69d4c3768db 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -237,6 +237,7 @@
 
 use crate::cmp::Ordering;
 use crate::fmt::{self, Debug, Display};
+use crate::intrinsics::is_nonoverlapping;
 use crate::marker::{PhantomData, Unsize};
 use crate::mem;
 use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
@@ -415,6 +416,12 @@ impl<T> Cell<T> {
     /// Swaps the values of two `Cell`s.
     /// Difference with `std::mem::swap` is that this function doesn't require `&mut` reference.
     ///
+    /// # 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.)
+    ///
     /// # Examples
     ///
     /// ```
@@ -430,14 +437,20 @@ impl<T> Cell<T> {
     #[stable(feature = "move_cell", since = "1.17.0")]
     pub fn swap(&self, other: &Self) {
         if ptr::eq(self, other) {
+            // Swapping wouldn't change anything.
             return;
         }
+        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");
+        }
         // 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
-        // either of these `Cell`s.
+        // 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.
         unsafe {
-            ptr::swap(self.value.get(), other.value.get());
+            ptr::swap_nonoverlapping(self.value.get(), other.value.get(), 1);
         }
     }