Skip to content

Commit 548250f

Browse files
committed
fix(soundness): disable interrupts on every RefCell flags change
Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
1 parent 3fe4b2e commit 548250f

File tree

2 files changed

+100
-36
lines changed

2 files changed

+100
-36
lines changed

src/interrupt_dropper.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use core::mem::ManuallyDrop;
2+
use core::ops::{Deref, DerefMut};
3+
4+
/// A wrapper for dropping values while interrupts are disabled.
5+
pub struct InterruptDropper<T> {
6+
inner: ManuallyDrop<T>,
7+
}
8+
9+
impl<T> From<T> for InterruptDropper<T> {
10+
#[inline]
11+
fn from(value: T) -> Self {
12+
Self {
13+
inner: ManuallyDrop::new(value),
14+
}
15+
}
16+
}
17+
18+
impl<T> InterruptDropper<T> {
19+
#[inline]
20+
pub fn into_inner(mut this: Self) -> T {
21+
// SAFETY: We never use `this` after this again.
22+
unsafe { ManuallyDrop::take(&mut this.inner) }
23+
}
24+
}
25+
26+
impl<T> Deref for InterruptDropper<T> {
27+
type Target = T;
28+
29+
#[inline]
30+
fn deref(&self) -> &Self::Target {
31+
self.inner.deref()
32+
}
33+
}
34+
35+
impl<T> DerefMut for InterruptDropper<T> {
36+
#[inline]
37+
fn deref_mut(&mut self) -> &mut Self::Target {
38+
self.inner.deref_mut()
39+
}
40+
}
41+
42+
impl<T> Drop for InterruptDropper<T> {
43+
#[inline]
44+
fn drop(&mut self) {
45+
let _guard = interrupts::disable();
46+
// Drop `inner` as while we can guarentee interrupts are disabled
47+
// SAFETY: This is not exposed to safe code and is not called more than once
48+
unsafe { ManuallyDrop::drop(&mut self.inner) }
49+
}
50+
}

src/lib.rs

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
6363
#![cfg_attr(target_os = "none", no_std)]
6464

65+
mod interrupt_dropper;
6566
#[cfg(not(target_os = "none"))]
6667
mod local_key;
6768

@@ -70,6 +71,7 @@ use core::cmp::Ordering;
7071
use core::ops::{Deref, DerefMut};
7172
use core::{fmt, mem};
7273

74+
use self::interrupt_dropper::InterruptDropper;
7375
#[cfg(not(target_os = "none"))]
7476
pub use self::local_key::LocalKeyExt;
7577

@@ -265,9 +267,10 @@ impl<T: ?Sized> InterruptRefCell<T> {
265267
#[cfg_attr(feature = "debug_interruptrefcell", track_caller)]
266268
pub fn try_borrow(&self) -> Result<InterruptRef<'_, T>, BorrowError> {
267269
let _guard = interrupts::disable();
268-
self.inner
269-
.try_borrow()
270-
.map(|inner| InterruptRef { inner, _guard })
270+
self.inner.try_borrow().map(|inner| {
271+
let inner = InterruptDropper::from(inner);
272+
InterruptRef { inner, _guard }
273+
})
271274
}
272275

273276
/// Mutably borrows the wrapped value.
@@ -335,9 +338,10 @@ impl<T: ?Sized> InterruptRefCell<T> {
335338
#[cfg_attr(feature = "debug_interruptrefcell", track_caller)]
336339
pub fn try_borrow_mut(&self) -> Result<InterruptRefMut<'_, T>, BorrowMutError> {
337340
let _guard = interrupts::disable();
338-
self.inner
339-
.try_borrow_mut()
340-
.map(|inner| InterruptRefMut { inner, _guard })
341+
self.inner.try_borrow_mut().map(|inner| {
342+
let inner = InterruptDropper::from(inner);
343+
InterruptRefMut { inner, _guard }
344+
})
341345
}
342346

343347
/// Returns a raw pointer to the underlying data in this cell.
@@ -417,6 +421,7 @@ impl<T: ?Sized> InterruptRefCell<T> {
417421
/// ```
418422
#[inline]
419423
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, BorrowError> {
424+
let _guard = interrupts::disable();
420425
self.inner.try_borrow_unguarded()
421426
}
422427
}
@@ -548,7 +553,7 @@ impl<T> From<T> for InterruptRefCell<T> {
548553
///
549554
/// See the [module-level documentation](self) for more.
550555
pub struct InterruptRef<'b, T: ?Sized + 'b> {
551-
inner: Ref<'b, T>,
556+
inner: InterruptDropper<Ref<'b, T>>,
552557
_guard: interrupts::Guard,
553558
}
554559

@@ -574,10 +579,9 @@ impl<'b, T: ?Sized> InterruptRef<'b, T> {
574579
#[must_use]
575580
#[inline]
576581
pub fn clone(orig: &InterruptRef<'b, T>) -> InterruptRef<'b, T> {
577-
InterruptRef {
578-
inner: Ref::clone(&orig.inner),
579-
_guard: interrupts::disable(),
580-
}
582+
let _guard = interrupts::disable();
583+
let inner = InterruptDropper::from(Ref::clone(&orig.inner));
584+
InterruptRef { inner, _guard }
581585
}
582586

583587
/// Makes a new `InterruptRef` for a component of the borrowed data.
@@ -604,10 +608,8 @@ impl<'b, T: ?Sized> InterruptRef<'b, T> {
604608
F: FnOnce(&T) -> &U,
605609
{
606610
let InterruptRef { inner, _guard } = orig;
607-
InterruptRef {
608-
inner: Ref::map(inner, f),
609-
_guard,
610-
}
611+
let inner = InterruptDropper::from(Ref::map(InterruptDropper::into_inner(inner), f));
612+
InterruptRef { inner, _guard }
611613
}
612614

613615
/// Makes a new `InterruptRef` for an optional component of the borrowed data. The
@@ -640,9 +642,15 @@ impl<'b, T: ?Sized> InterruptRef<'b, T> {
640642
F: FnOnce(&T) -> Option<&U>,
641643
{
642644
let InterruptRef { inner, _guard } = orig;
643-
match Ref::filter_map(inner, f) {
644-
Ok(inner) => Ok(InterruptRef { inner, _guard }),
645-
Err(inner) => Err(InterruptRef { inner, _guard }),
645+
match Ref::filter_map(InterruptDropper::into_inner(inner), f) {
646+
Ok(inner) => {
647+
let inner = InterruptDropper::from(inner);
648+
Ok(InterruptRef { inner, _guard })
649+
}
650+
Err(inner) => {
651+
let inner = InterruptDropper::from(inner);
652+
Err(InterruptRef { inner, _guard })
653+
}
646654
}
647655
}
648656

@@ -674,15 +682,16 @@ impl<'b, T: ?Sized> InterruptRef<'b, T> {
674682
where
675683
F: FnOnce(&T) -> (&U, &V),
676684
{
677-
let (a, b) = Ref::map_split(orig.inner, f);
685+
let _guard = interrupts::disable();
686+
let (a, b) = Ref::map_split(InterruptDropper::into_inner(orig.inner), f);
678687
(
679688
InterruptRef {
680-
inner: a,
681-
_guard: orig._guard,
689+
inner: InterruptDropper::from(a),
690+
_guard,
682691
},
683692
InterruptRef {
684-
inner: b,
685-
_guard: interrupts::disable(),
693+
inner: InterruptDropper::from(b),
694+
_guard: orig._guard,
686695
},
687696
)
688697
}
@@ -730,10 +739,8 @@ impl<'b, T: ?Sized> InterruptRefMut<'b, T> {
730739
F: FnOnce(&mut T) -> &mut U,
731740
{
732741
let InterruptRefMut { inner, _guard } = orig;
733-
InterruptRefMut {
734-
inner: RefMut::map(inner, f),
735-
_guard,
736-
}
742+
let inner = InterruptDropper::from(RefMut::map(InterruptDropper::into_inner(inner), f));
743+
InterruptRefMut { inner, _guard }
737744
}
738745

739746
/// Makes a new `InterruptRefMut` for an optional component of the borrowed data. The
@@ -774,9 +781,15 @@ impl<'b, T: ?Sized> InterruptRefMut<'b, T> {
774781
F: FnOnce(&mut T) -> Option<&mut U>,
775782
{
776783
let InterruptRefMut { inner, _guard } = orig;
777-
match RefMut::filter_map(inner, f) {
778-
Ok(inner) => Ok(InterruptRefMut { inner, _guard }),
779-
Err(inner) => Err(InterruptRefMut { inner, _guard }),
784+
match RefMut::filter_map(InterruptDropper::into_inner(inner), f) {
785+
Ok(inner) => {
786+
let inner = InterruptDropper::from(inner);
787+
Ok(InterruptRefMut { inner, _guard })
788+
}
789+
Err(inner) => {
790+
let inner = InterruptDropper::from(inner);
791+
Err(InterruptRefMut { inner, _guard })
792+
}
780793
}
781794
}
782795

@@ -813,15 +826,16 @@ impl<'b, T: ?Sized> InterruptRefMut<'b, T> {
813826
where
814827
F: FnOnce(&mut T) -> (&mut U, &mut V),
815828
{
816-
let (a, b) = RefMut::map_split(orig.inner, f);
829+
let _guard = interrupts::disable();
830+
let (a, b) = RefMut::map_split(InterruptDropper::into_inner(orig.inner), f);
817831
(
818832
InterruptRefMut {
819-
inner: a,
820-
_guard: orig._guard,
833+
inner: InterruptDropper::from(a),
834+
_guard,
821835
},
822836
InterruptRefMut {
823-
inner: b,
824-
_guard: interrupts::disable(),
837+
inner: InterruptDropper::from(b),
838+
_guard: orig._guard,
825839
},
826840
)
827841
}
@@ -831,7 +845,7 @@ impl<'b, T: ?Sized> InterruptRefMut<'b, T> {
831845
///
832846
/// See the [module-level documentation](self) for more.
833847
pub struct InterruptRefMut<'b, T: ?Sized + 'b> {
834-
inner: RefMut<'b, T>,
848+
inner: InterruptDropper<RefMut<'b, T>>,
835849
_guard: interrupts::Guard,
836850
}
837851

0 commit comments

Comments
 (0)