-
Notifications
You must be signed in to change notification settings - Fork 731
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dropping DefaultGuard
in another thread doesn't cause it to get cleaned up properly
#2482
Comments
This is related to #1657, but is a different bug with a different root cause. |
We should definitely make the guard In the meantime, though, we may want to investigate alternate solutions for 0.1.x. I agree that the potential performance penalty for making the guard handle the case where it's sent across threads is quite unfortunate, especially if it's paid in all uses of the scoped dispatcher API... Alternative approaches include adding a new version of the |
I can make a PR for v0.2.x in the next few days, as that seems straightforward. v0.1.x is a little less clear.
However, there is no alternative API for Also, making an implementation note here: #1001 used (a trivial) unsafe impl<'a> Sync for Entered<'a> {} I believe it is possible to do something similar without use std::marker::PhantomData;
trait NotSend: Sync {}
#[derive(Default)]
struct Foo {
_not_send: PhantomData<dyn NotSend>,
}
fn main() {
let f = Foo::default();
std::thread::spawn(move || {
drop(f);
});
}
|
The `Drop` impl of `DefaultGuard` modifies the `CURRENT_STATE` thread local, assuming it to be the same thread local it was constructed with. However, because `DefaultGuard` is `Send`, that may be a different thread local. Therefore, we should mark `DefaultGuard` as `!Send`.
Bug Report
Crates / Version
tracing_core
0.1.30
and0.2.x
(master)Platform
This issue is not platform specific. I've reproduced it on the rust playground and replit (Linux).
Description
The
Drop
impl ofDefaultGuard
modifies theCURRENT_STATE
thread local, assuming it to be the same thread local it was constructed with.tracing/tracing-core/src/dispatch.rs
Lines 207 to 212 in a0126b2
tracing/tracing-core/src/dispatch.rs
Lines 1048 to 1063 in a0126b2
However, because
DefaultGuard
isSend
, that may be a different thread local.This bug is further obfuscated by an optimization: The dispatcher keeps track of a global
SCOPED_COUNT
, which must be non-zero to reproduce this bug:tracing/tracing-core/src/dispatch.rs
Lines 414 to 425 in a0126b2
In my repro example, I create a
NoopCollect
to ensureSCOPED_COUNT
is non-zero.Repro
Code for the 0.2.x repro:
Suggestions
Either make
DefaultGuard
!Send
, which is what was done for spanEntered
guards in #698, or makeDefaultGuard
track theCURRENT_STATE
associated with the thread it was constructed in.Even though it would be a breaking API change (and would need to wait for 0.2.x), I prefer the
!Send
approach because:Send
futures. Somebody might write an async function that thinks it's within a certain guard, but isn't if work stealing happens.DefaultGuard
track theCURRENT_STATE
it was constructed with would likely require anArc
and aMutex
instead of the currentRefCell
that's used. There would be a performance penalty.The text was updated successfully, but these errors were encountered: