Skip to content

Commit 79c4ae5

Browse files
committed
impl Drop for AtomicCell
1 parent b947740 commit 79c4ae5

File tree

1 file changed

+31
-3
lines changed

1 file changed

+31
-3
lines changed

crossbeam-utils/src/atomic/atomic_cell.rs

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::primitive::sync::atomic::{self, AtomicBool};
55
use core::cell::UnsafeCell;
66
use core::cmp;
77
use core::fmt;
8-
use core::mem::{self, MaybeUninit};
8+
use core::mem::{self, ManuallyDrop, MaybeUninit};
99
use core::sync::atomic::Ordering;
1010

1111
use core::ptr;
@@ -39,6 +39,10 @@ pub struct AtomicCell<T> {
3939
///
4040
/// Using MaybeUninit to prevent code outside the cell from observing partially initialized state:
4141
/// <https://github.com/crossbeam-rs/crossbeam/issues/833>
42+
///
43+
/// Note:
44+
/// - we'll never store uninitialized `T` due to our API only using initialized `T`.
45+
/// - this `MaybeUninit` does *not* fix <https://github.com/crossbeam-rs/crossbeam/issues/315>.
4246
value: UnsafeCell<MaybeUninit<T>>,
4347
}
4448

@@ -68,6 +72,9 @@ impl<T> AtomicCell<T> {
6872

6973
/// Consumes the atomic and returns the contained value.
7074
///
75+
/// This is safe because passing `self` by value guarantees that no other threads are
76+
/// concurrently accessing the atomic data.
77+
///
7178
/// # Examples
7279
///
7380
/// ```
@@ -79,8 +86,13 @@ impl<T> AtomicCell<T> {
7986
/// assert_eq!(v, 7);
8087
/// ```
8188
pub fn into_inner(self) -> T {
82-
// SAFETY: we'll never store uninitialized `T`
83-
unsafe { self.value.into_inner().assume_init() }
89+
let this = ManuallyDrop::new(self);
90+
// SAFETY:
91+
// - passing `self` by value guarantees that no other threads are concurrently
92+
// accessing the atomic data
93+
// - the raw pointer passed in is valid because we got it from an owned value.
94+
// - `ManuallyDrop` prevents double dropping `T`
95+
unsafe { this.as_ptr().read() }
8496
}
8597

8698
/// Returns `true` if operations on values of this type are lock-free.
@@ -294,6 +306,22 @@ impl<T: Copy + Eq> AtomicCell<T> {
294306
}
295307
}
296308

309+
// `MaybeUninit` prevents `T` from being dropped, we need to implement `Drop`
310+
// for `AtomicCell` to avoid leaks of non-`Copy` types.
311+
impl<T> Drop for AtomicCell<T> {
312+
fn drop(&mut self) {
313+
if mem::needs_drop::<T>() {
314+
// SAFETY:
315+
// - the mutable reference guarantees that no other threads are concurrently accessing the atomic data
316+
// - the raw pointer passed in is valid because we got it from a reference
317+
// - `MaybeUninit` prevents double dropping `T`
318+
unsafe {
319+
drop(self.as_ptr().read());
320+
}
321+
}
322+
}
323+
}
324+
297325
macro_rules! impl_arithmetic {
298326
($t:ty, fallback, $example:tt) => {
299327
impl AtomicCell<$t> {

0 commit comments

Comments
 (0)