Skip to content

Commit 125baea

Browse files
committed
Use NonNull pointer in the place of references in AtomicRef and
`AtomicRefMut` to avoid `noalias` related soundness bug.
1 parent d0aefef commit 125baea

File tree

1 file changed

+30
-15
lines changed

1 file changed

+30
-15
lines changed

src/lib.rs

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ use core::cell::UnsafeCell;
4848
use core::cmp;
4949
use core::fmt;
5050
use core::fmt::{Debug, Display};
51+
use core::marker::PhantomData;
5152
use core::ops::{Deref, DerefMut};
53+
use core::ptr::NonNull;
5254
use core::sync::atomic;
5355
use core::sync::atomic::AtomicUsize;
5456

@@ -116,7 +118,7 @@ impl<T: ?Sized> AtomicRefCell<T> {
116118
pub fn borrow(&self) -> AtomicRef<T> {
117119
match AtomicBorrowRef::try_new(&self.borrow) {
118120
Ok(borrow) => AtomicRef {
119-
value: unsafe { &*self.value.get() },
121+
value: unsafe { NonNull::new_unchecked(self.value.get()) },
120122
borrow,
121123
},
122124
Err(s) => panic!("{}", s),
@@ -129,7 +131,7 @@ impl<T: ?Sized> AtomicRefCell<T> {
129131
pub fn try_borrow(&self) -> Result<AtomicRef<T>, BorrowError> {
130132
match AtomicBorrowRef::try_new(&self.borrow) {
131133
Ok(borrow) => Ok(AtomicRef {
132-
value: unsafe { &*self.value.get() },
134+
value: unsafe { NonNull::new_unchecked(self.value.get()) },
133135
borrow,
134136
}),
135137
Err(_) => Err(BorrowError { _private: () }),
@@ -141,8 +143,9 @@ impl<T: ?Sized> AtomicRefCell<T> {
141143
pub fn borrow_mut(&self) -> AtomicRefMut<T> {
142144
match AtomicBorrowRefMut::try_new(&self.borrow) {
143145
Ok(borrow) => AtomicRefMut {
144-
value: unsafe { &mut *self.value.get() },
146+
value: unsafe { NonNull::new_unchecked(self.value.get()) },
145147
borrow,
148+
marker: PhantomData,
146149
},
147150
Err(s) => panic!("{}", s),
148151
}
@@ -154,8 +157,9 @@ impl<T: ?Sized> AtomicRefCell<T> {
154157
pub fn try_borrow_mut(&self) -> Result<AtomicRefMut<T>, BorrowMutError> {
155158
match AtomicBorrowRefMut::try_new(&self.borrow) {
156159
Ok(borrow) => Ok(AtomicRefMut {
157-
value: unsafe { &mut *self.value.get() },
160+
value: unsafe { NonNull::new_unchecked(self.value.get()) },
158161
borrow,
162+
marker: PhantomData,
159163
}),
160164
Err(_) => Err(BorrowMutError { _private: () }),
161165
}
@@ -366,7 +370,7 @@ impl<'b> Clone for AtomicBorrowRef<'b> {
366370

367371
/// A wrapper type for an immutably borrowed value from an `AtomicRefCell<T>`.
368372
pub struct AtomicRef<'b, T: ?Sized + 'b> {
369-
value: &'b T,
373+
value: NonNull<T>,
370374
borrow: AtomicBorrowRef<'b>,
371375
}
372376

@@ -375,7 +379,8 @@ impl<'b, T: ?Sized> Deref for AtomicRef<'b, T> {
375379

376380
#[inline]
377381
fn deref(&self) -> &T {
378-
self.value
382+
// SAFETY: We hold shared borrow of the value.
383+
unsafe { self.value.as_ref() }
379384
}
380385
}
381386

@@ -396,7 +401,7 @@ impl<'b, T: ?Sized> AtomicRef<'b, T> {
396401
F: FnOnce(&T) -> &U,
397402
{
398403
AtomicRef {
399-
value: f(orig.value),
404+
value: NonNull::from(f(&*orig)),
400405
borrow: orig.borrow,
401406
}
402407
}
@@ -408,7 +413,7 @@ impl<'b, T: ?Sized> AtomicRef<'b, T> {
408413
F: FnOnce(&T) -> Option<&U>,
409414
{
410415
Some(AtomicRef {
411-
value: f(orig.value)?,
416+
value: NonNull::from(f(&*orig)?),
412417
borrow: orig.borrow,
413418
})
414419
}
@@ -418,48 +423,58 @@ impl<'b, T: ?Sized> AtomicRefMut<'b, T> {
418423
/// Make a new `AtomicRefMut` for a component of the borrowed data, e.g. an enum
419424
/// variant.
420425
#[inline]
421-
pub fn map<U: ?Sized, F>(orig: AtomicRefMut<'b, T>, f: F) -> AtomicRefMut<'b, U>
426+
pub fn map<U: ?Sized, F>(mut orig: AtomicRefMut<'b, T>, f: F) -> AtomicRefMut<'b, U>
422427
where
423428
F: FnOnce(&mut T) -> &mut U,
424429
{
425430
AtomicRefMut {
426-
value: f(orig.value),
431+
value: NonNull::from(f(&mut *orig)),
427432
borrow: orig.borrow,
433+
marker: PhantomData,
428434
}
429435
}
430436

431437
/// Make a new `AtomicRefMut` for an optional component of the borrowed data.
432438
#[inline]
433-
pub fn filter_map<U: ?Sized, F>(orig: AtomicRefMut<'b, T>, f: F) -> Option<AtomicRefMut<'b, U>>
439+
pub fn filter_map<U: ?Sized, F>(
440+
mut orig: AtomicRefMut<'b, T>,
441+
f: F,
442+
) -> Option<AtomicRefMut<'b, U>>
434443
where
435444
F: FnOnce(&mut T) -> Option<&mut U>,
436445
{
437446
Some(AtomicRefMut {
438-
value: f(orig.value)?,
447+
value: NonNull::from(f(&mut *orig)?),
439448
borrow: orig.borrow,
449+
marker: PhantomData,
440450
})
441451
}
442452
}
443453

444454
/// A wrapper type for a mutably borrowed value from an `AtomicRefCell<T>`.
445455
pub struct AtomicRefMut<'b, T: ?Sized + 'b> {
446-
value: &'b mut T,
456+
value: NonNull<T>,
447457
borrow: AtomicBorrowRefMut<'b>,
458+
// `NonNull` is covariant over `T`, but this is used in place of a mutable
459+
// reference so we need to be invariant over `T`.
460+
marker: PhantomData<&'b mut T>,
448461
}
449462

450463
impl<'b, T: ?Sized> Deref for AtomicRefMut<'b, T> {
451464
type Target = T;
452465

453466
#[inline]
454467
fn deref(&self) -> &T {
455-
self.value
468+
// SAFETY: We hold an exclusive borrow of the value.
469+
unsafe { self.value.as_ref() }
456470
}
457471
}
458472

459473
impl<'b, T: ?Sized> DerefMut for AtomicRefMut<'b, T> {
460474
#[inline]
461475
fn deref_mut(&mut self) -> &mut T {
462-
self.value
476+
// SAFETY: We hold an exclusive borrow of the value.
477+
unsafe { self.value.as_mut() }
463478
}
464479
}
465480

0 commit comments

Comments
 (0)