core: drop dispatch object outside of mutable borrow section (#522)

With this change we replace DefaultGuard's drop implementation with a
version that no longer drops the previous dispatch object while the
comprising RefCell is borrowed mutably. In issue #521 we have seen how
this can back fire and result in a panic.
This patch is based on a suggestion by @hawkw (thanks for the quick
feedback!).

Fixes: #521
This commit is contained in:
Daniel Müller 2020-01-10 09:37:07 -08:00 committed by Eliza Weisman
parent d0b22bb331
commit 4ba701bf19

View File

@ -669,9 +669,13 @@ impl Drop for DefaultGuard {
#[inline]
fn drop(&mut self) {
if let Some(dispatch) = self.0.take() {
let _ = CURRENT_STATE.try_with(|state| {
*state.default.borrow_mut() = dispatch;
});
// Replace the dispatcher and then drop the old one outside
// of the thread-local context. Dropping the dispatch may
// lead to the drop of a subscriber which, in the process,
// could then also attempt to access the same thread local
// state -- causing a clash.
let prev = CURRENT_STATE.try_with(|state| state.default.replace(dispatch));
drop(prev)
}
}
}