-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Catch panics/unwinding in destruction of TLS values #105426
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
Conversation
r? @m-ou-se (rustbot has picked a reviewer for you, use r? to override) |
e55bcb7
to
b7691da
Compare
b7691da
to
f6a6177
Compare
library/std/src/thread/local.rs
Outdated
if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { | ||
let ptr = ptr as *mut Key<T>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is panic::AssertUnwindSafe
correct here? Is it allowed to move let ptr =
down to limit its scope?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You only have to put the drop()
line in the catch_unwind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@m-ou-se Unfortunately the dereferencing of raw pointers needs to be done inside the unsafe
block and it cannot be done in a separate unsafe
block as we need the variable value
(unless we have a quite long unsafe
block). I've restored the position of let ptr = ...
line as it neither requires catch_unwind
nor unsafe
and keeps the diff smaller. Is this what you had in mind?
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
library/std/src/thread/local.rs
Outdated
let value = (*ptr).inner.take(); | ||
(*ptr).dtor_state.set(DtorState::RunningOrHasRun); | ||
drop(value); | ||
})) { | ||
rtabort!("destructor panicked"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you change the panic message to "thread local panicked on drop"? Then it matches the message of thread results:
rust/library/std/src/thread/mod.rs
Lines 1424 to 1428 in 6a20f7d
if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| { | |
*self.result.get_mut() = None; | |
})) { | |
rtabort!("thread result panicked on drop"); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great hint, thank & done
`destroy_value` is/can be called from C code (libc). Unwinding from Rust to C code is undefined behavior, which is why unwinding is caught here.
f6a6177
to
04a6f22
Compare
@rustbot label -S-waiting-on-author +S-waiting-on-review |
@bors r+ |
☀️ Test successful - checks-actions |
Finished benchmarking commit (7c99186): comparison URL. Overall result: ❌✅ regressions and improvements - ACTION NEEDEDNext Steps: If you can justify the regressions found in this perf run, please indicate this with @rustbot label: +perf-regression Instruction countThis is a highly reliable metric that was used to determine the overall result at the top of this comment.
Max RSS (memory usage)ResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
CyclesResultsThis is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.
|
@m-ou-se @flba-eb I'm not sure I understand where this perf regression is coming from. This does not look like noise as the impact is pretty broad and impacts some of the more stable benchmarks. Some of the benchmarks are showing increased activity in LLVM which might be caused by extra code gen, but this is not the case in all regressions and it certainly doesn't explain the improvements. Any thoughts? |
Good question, @rylev . I don't know how CatchUnwind is implemented but I guess it adds a special symbol on the stack which let's the unwinding stop early. On qnx it stops a loop which would run endlessly otherwise (when drop panics) -- I could imagine that on other systems unwinding have a similar issue but have some safety counter to also stop after a high number of e.g. checked frames. In such a case unwinding would stop earlier now (at CatchUnwind instead after reaching some number). But this is really some very wild guess... It also would only make sense if the improved test cases have drop calls that panic. |
…, r=m-ou-se Catch panics/unwinding in destruction of TLS values `destroy_value` is/can be called from C code (libc). Unwinding from Rust to C code is undefined behavior, which is why unwinding is caught here. This problem caused an infinite loop inside the unwinding code when running `src/test/ui/threads-sendsync/issue-24313.rs` on a tier 3 target (QNX/Neutrino) on aarch64. See also https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Infinite.20unwinding.20bug.
destroy_value
is/can be called from C code (libc). Unwinding from Rust to C code is undefined behavior, which is why unwinding is caught here.This problem caused an infinite loop inside the unwinding code when running
src/test/ui/threads-sendsync/issue-24313.rs
on a tier 3 target (QNX/Neutrino) on aarch64.See also https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Infinite.20unwinding.20bug.