diff --git a/tests/atomic.rs b/tests/atomic.rs index 01b0565c..e33f936b 100644 --- a/tests/atomic.rs +++ b/tests/atomic.rs @@ -40,3 +40,39 @@ fn invalid_get_mut() { let _ = unsafe { *(*v1.get()).get_mut() }; }); } + +#[test] +#[should_panic] +fn atomic_load_on_drop_in_panic_crashes() { + struct AtomicLoadOnDrop(AtomicUsize); + + impl AtomicLoadOnDrop { + fn new() -> Self { + Self(AtomicUsize::new(0)) + } + } + + impl Drop for AtomicLoadOnDrop { + fn drop(&mut self) { + let _ = self.0.load(SeqCst); + } + } + + loom::model(|| { + let a = AtomicLoadOnDrop::new(); + + // Moving `AtomicLoadOnDrop` into a thread will trigger `drop` when the + // thread is dropped. + thread::spawn(move || { + let _a = a; + }); + + // Panic the parent thread. + // + // Without a fix, the `AtomicLoadOnDrop` drops _after_ the + // `loom::rt::scheduler::STATE` thread local is dropped. Since atomics + // use `STATE` to track accesses, dropping `AtomicLoadOnDrop` causes an + // access to an unset `RefCell`. + panic!(); + }); +}