diff --git a/crossbeam-utils/src/atomic/atomic_cell.rs b/crossbeam-utils/src/atomic/atomic_cell.rs index 891425e48..3225ff1cc 100644 --- a/crossbeam-utils/src/atomic/atomic_cell.rs +++ b/crossbeam-utils/src/atomic/atomic_cell.rs @@ -5,7 +5,7 @@ use crate::primitive::sync::atomic::{self, AtomicBool}; use core::cell::UnsafeCell; use core::cmp; use core::fmt; -use core::mem; +use core::mem::{self, MaybeUninit}; use core::sync::atomic::Ordering; use core::ptr; @@ -30,13 +30,16 @@ use super::seq_lock::SeqLock; /// [`Acquire`]: std::sync::atomic::Ordering::Acquire /// [`Release`]: std::sync::atomic::Ordering::Release #[repr(transparent)] -pub struct AtomicCell { +pub struct AtomicCell { /// The inner value. /// /// If this value can be transmuted into a primitive atomic type, it will be treated as such. /// Otherwise, all potentially concurrent operations on this data will be protected by a global /// lock. - value: UnsafeCell, + /// + /// Using MaybeUninit to prevent code outside the cell from observing partially initialized state: + /// + value: UnsafeCell>, } unsafe impl Send for AtomicCell {} @@ -59,7 +62,7 @@ impl AtomicCell { /// ``` pub const fn new(val: T) -> AtomicCell { AtomicCell { - value: UnsafeCell::new(val), + value: UnsafeCell::new(MaybeUninit::new(val)), } } @@ -76,7 +79,8 @@ impl AtomicCell { /// assert_eq!(v, 7); /// ``` pub fn into_inner(self) -> T { - self.value.into_inner() + // SAFETY: we'll never store uninitialized `T` + unsafe { self.value.into_inner().assume_init() } } /// Returns `true` if operations on values of this type are lock-free. @@ -129,7 +133,7 @@ impl AtomicCell { drop(self.swap(val)); } else { unsafe { - atomic_store(self.value.get(), val); + atomic_store(self.as_ptr(), val); } } } @@ -148,11 +152,9 @@ impl AtomicCell { /// assert_eq!(a.load(), 8); /// ``` pub fn swap(&self, val: T) -> T { - unsafe { atomic_swap(self.value.get(), val) } + unsafe { atomic_swap(self.as_ptr(), val) } } -} -impl AtomicCell { /// Returns a raw pointer to the underlying data in this atomic cell. /// /// # Examples @@ -166,7 +168,7 @@ impl AtomicCell { /// ``` #[inline] pub fn as_ptr(&self) -> *mut T { - self.value.get() + self.value.get() as *mut T } } @@ -202,7 +204,7 @@ impl AtomicCell { /// assert_eq!(a.load(), 7); /// ``` pub fn load(&self) -> T { - unsafe { atomic_load(self.value.get()) } + unsafe { atomic_load(self.as_ptr()) } } } @@ -254,7 +256,7 @@ impl AtomicCell { /// assert_eq!(a.load(), 2); /// ``` pub fn compare_exchange(&self, current: T, new: T) -> Result { - unsafe { atomic_compare_exchange_weak(self.value.get(), current, new) } + unsafe { atomic_compare_exchange_weak(self.as_ptr(), current, new) } } /// Fetches the value, and applies a function to it that returns an optional @@ -311,8 +313,8 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_add(&self, val: $t) -> $t { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = value.wrapping_add(val); old @@ -334,8 +336,8 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_sub(&self, val: $t) -> $t { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = value.wrapping_sub(val); old @@ -355,8 +357,8 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_and(&self, val: $t) -> $t { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value &= val; old @@ -376,8 +378,8 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_nand(&self, val: $t) -> $t { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = !(old & val); old @@ -397,8 +399,8 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_or(&self, val: $t) -> $t { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value |= val; old @@ -418,8 +420,8 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_xor(&self, val: $t) -> $t { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value ^= val; old @@ -440,8 +442,8 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_max(&self, val: $t) -> $t { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = cmp::max(old, val); old @@ -462,8 +464,8 @@ macro_rules! impl_arithmetic { /// ``` #[inline] pub fn fetch_min(&self, val: $t) -> $t { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = cmp::min(old, val); old @@ -489,11 +491,11 @@ macro_rules! impl_arithmetic { #[inline] pub fn fetch_add(&self, val: $t) -> $t { if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.value.get() as *const $atomic) }; + let a = unsafe { &*(self.as_ptr() as *const $atomic) }; a.fetch_add(val, Ordering::AcqRel) } else { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = value.wrapping_add(val); old @@ -517,11 +519,11 @@ macro_rules! impl_arithmetic { #[inline] pub fn fetch_sub(&self, val: $t) -> $t { if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.value.get() as *const $atomic) }; + let a = unsafe { &*(self.as_ptr() as *const $atomic) }; a.fetch_sub(val, Ordering::AcqRel) } else { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = value.wrapping_sub(val); old @@ -543,11 +545,11 @@ macro_rules! impl_arithmetic { #[inline] pub fn fetch_and(&self, val: $t) -> $t { if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.value.get() as *const $atomic) }; + let a = unsafe { &*(self.as_ptr() as *const $atomic) }; a.fetch_and(val, Ordering::AcqRel) } else { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value &= val; old @@ -569,11 +571,11 @@ macro_rules! impl_arithmetic { #[inline] pub fn fetch_nand(&self, val: $t) -> $t { if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.value.get() as *const $atomic) }; + let a = unsafe { &*(self.as_ptr() as *const $atomic) }; a.fetch_nand(val, Ordering::AcqRel) } else { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = !(old & val); old @@ -595,11 +597,11 @@ macro_rules! impl_arithmetic { #[inline] pub fn fetch_or(&self, val: $t) -> $t { if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.value.get() as *const $atomic) }; + let a = unsafe { &*(self.as_ptr() as *const $atomic) }; a.fetch_or(val, Ordering::AcqRel) } else { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value |= val; old @@ -621,11 +623,11 @@ macro_rules! impl_arithmetic { #[inline] pub fn fetch_xor(&self, val: $t) -> $t { if can_transmute::<$t, $atomic>() { - let a = unsafe { &*(self.value.get() as *const $atomic) }; + let a = unsafe { &*(self.as_ptr() as *const $atomic) }; a.fetch_xor(val, Ordering::AcqRel) } else { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value ^= val; old @@ -651,8 +653,8 @@ macro_rules! impl_arithmetic { // TODO: Atomic*::fetch_max requires Rust 1.45. self.fetch_update(|old| Some(cmp::max(old, val))).unwrap() } else { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = cmp::max(old, val); old @@ -678,8 +680,8 @@ macro_rules! impl_arithmetic { // TODO: Atomic*::fetch_min requires Rust 1.45. self.fetch_update(|old| Some(cmp::min(old, val))).unwrap() } else { - let _guard = lock(self.value.get() as usize).write(); - let value = unsafe { &mut *(self.value.get()) }; + let _guard = lock(self.as_ptr() as usize).write(); + let value = unsafe { &mut *(self.as_ptr()) }; let old = *value; *value = cmp::min(old, val); old @@ -738,7 +740,7 @@ impl AtomicCell { /// ``` #[inline] pub fn fetch_and(&self, val: bool) -> bool { - let a = unsafe { &*(self.value.get() as *const AtomicBool) }; + let a = unsafe { &*(self.as_ptr() as *const AtomicBool) }; a.fetch_and(val, Ordering::AcqRel) } @@ -762,7 +764,7 @@ impl AtomicCell { /// ``` #[inline] pub fn fetch_nand(&self, val: bool) -> bool { - let a = unsafe { &*(self.value.get() as *const AtomicBool) }; + let a = unsafe { &*(self.as_ptr() as *const AtomicBool) }; a.fetch_nand(val, Ordering::AcqRel) } @@ -783,7 +785,7 @@ impl AtomicCell { /// ``` #[inline] pub fn fetch_or(&self, val: bool) -> bool { - let a = unsafe { &*(self.value.get() as *const AtomicBool) }; + let a = unsafe { &*(self.as_ptr() as *const AtomicBool) }; a.fetch_or(val, Ordering::AcqRel) } @@ -804,7 +806,7 @@ impl AtomicCell { /// ``` #[inline] pub fn fetch_xor(&self, val: bool) -> bool { - let a = unsafe { &*(self.value.get() as *const AtomicBool) }; + let a = unsafe { &*(self.as_ptr() as *const AtomicBool) }; a.fetch_xor(val, Ordering::AcqRel) } }