@@ -127,7 +127,41 @@ impl Scheduler {
127
127
panic ! ( "cannot access Loom execution state from outside a Loom model. \
128
128
are you accessing a Loom synchronization primitive from outside a Loom test (a call to `model` or `check`)?")
129
129
}
130
- STATE . with ( |state| f ( & mut state. borrow_mut ( ) ) )
130
+ STATE . with ( |state| {
131
+ // When unwinding after a panic, `STATE` is unset before `Scheduler` is dropped.
132
+ // However, `Scheduler::queued_spawn` could hold loom objects which would try to use
133
+ // `STATE` when they are dropped. Because of that, we need to clear `queued_spawn`
134
+ // while STATE is still set. Since `STATE` has an exclusive reference (&mut) to
135
+ // `Scheduler::queued_spawn`, we also need to use `STATE` ourselves for accessing them,
136
+ // but drop our `RefMut` before the dropping of `queued_spawn` happens.
137
+ //
138
+ // To implement this, we exploit the fact that the struct fields of `DropGuard`
139
+ // are dropped in declaration order, and move `queued_spawn`in `DropGuard::drop`
140
+ // to the second struct field of `DropGuard` (replacing it with an empty `VecDeque`).
141
+ // Then, the destructor first drops the `RefMut` (thereby allowing `STATE` to be
142
+ // borrowed again), and then the former `queued_spawn` value (possibly accessing `STATE`).
143
+ struct DropGuard < ' a , ' b > (
144
+ std:: cell:: RefMut < ' a , State < ' b > > ,
145
+ VecDeque < Box < dyn FnOnce ( ) > > ,
146
+ ) ;
147
+ impl < ' a , ' b > Drop for DropGuard < ' a , ' b > {
148
+ fn drop ( & mut self ) {
149
+ if std:: thread:: panicking ( ) {
150
+ self . 1 = std:: mem:: take ( self . 0 . queued_spawn ) ;
151
+ }
152
+ }
153
+ }
154
+ impl < ' a , ' b > DropGuard < ' a , ' b > {
155
+ fn run < F , R > ( & mut self , f : F ) -> R
156
+ where
157
+ F : FnOnce ( & mut State < ' b > ) -> R ,
158
+ {
159
+ f ( & mut self . 0 )
160
+ }
161
+ }
162
+ let mut guard = DropGuard ( state. borrow_mut ( ) , Default :: default ( ) ) ;
163
+ guard. run ( f)
164
+ } )
131
165
}
132
166
}
133
167
0 commit comments