Properly abort when thread result panics on drop.
This commit is contained in:
parent
5226395d6f
commit
7a481ff8a4
2 changed files with 26 additions and 24 deletions
|
@ -363,6 +363,11 @@ extern crate std as realstd;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
|
// The runtime entry point and a few unstable public functions used by the
|
||||||
|
// compiler
|
||||||
|
#[macro_use]
|
||||||
|
pub mod rt;
|
||||||
|
|
||||||
// The Rust prelude
|
// The Rust prelude
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
|
@ -547,11 +552,6 @@ pub mod arch {
|
||||||
#[stable(feature = "simd_x86", since = "1.27.0")]
|
#[stable(feature = "simd_x86", since = "1.27.0")]
|
||||||
pub use std_detect::is_x86_feature_detected;
|
pub use std_detect::is_x86_feature_detected;
|
||||||
|
|
||||||
// The runtime entry point and a few unstable public functions used by the
|
|
||||||
// compiler
|
|
||||||
#[macro_use]
|
|
||||||
pub mod rt;
|
|
||||||
|
|
||||||
// Platform-abstraction modules
|
// Platform-abstraction modules
|
||||||
mod sys;
|
mod sys;
|
||||||
mod sys_common;
|
mod sys_common;
|
||||||
|
|
|
@ -1287,29 +1287,31 @@ unsafe impl<'scope, T: Sync> Sync for Packet<'scope, T> {}
|
||||||
|
|
||||||
impl<'scope, T> Drop for Packet<'scope, T> {
|
impl<'scope, T> Drop for Packet<'scope, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
// If this packet was for a thread that ran in a scope, the thread
|
||||||
|
// panicked, and nobody consumed the panic payload, we make sure
|
||||||
|
// the scope function will panic.
|
||||||
|
let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
|
||||||
|
// Drop the result without causing unwinding.
|
||||||
|
// This is only relevant for threads that aren't join()ed, as
|
||||||
|
// join() will take the `result` and set it to None, such that
|
||||||
|
// there is nothing left to drop here.
|
||||||
|
// If this panics, we should handle that, because we're outside the
|
||||||
|
// outermost `catch_unwind` of our thread.
|
||||||
|
// We just abort in that case, since there's nothing else we can do.
|
||||||
|
// (And even if we tried to handle it somehow, we'd also need to handle
|
||||||
|
// the case where the panic payload we get out of it also panics on
|
||||||
|
// drop, and so on. See issue #86027.)
|
||||||
|
if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| {
|
||||||
|
*self.result.get_mut() = None;
|
||||||
|
})) {
|
||||||
|
rtabort!("thread result panicked on drop");
|
||||||
|
}
|
||||||
// Book-keeping so the scope knows when it's done.
|
// Book-keeping so the scope knows when it's done.
|
||||||
if let Some(scope) = self.scope {
|
if let Some(scope) = self.scope {
|
||||||
// If this packet was for a thread that ran in a scope, the thread
|
|
||||||
// panicked, and nobody consumed the panic payload, we make sure
|
|
||||||
// the scope function will panic.
|
|
||||||
let unhandled_panic = matches!(self.result.get_mut(), Some(Err(_)));
|
|
||||||
// Drop the result before decrementing the number of running
|
|
||||||
// threads, because the Drop implementation might still use things
|
|
||||||
// it borrowed from 'scope.
|
|
||||||
// This is only relevant for threads that aren't join()ed, as
|
|
||||||
// join() will take the `result` and set it to None, such that
|
|
||||||
// there is nothing left to drop here.
|
|
||||||
// If this drop panics, that just results in an abort, because
|
|
||||||
// we're outside of the outermost `catch_unwind` of our thread.
|
|
||||||
// The same happens for detached non-scoped threads when dropping
|
|
||||||
// their ignored return value (or panic payload) panics, so
|
|
||||||
// there's no need to try to do anything better.
|
|
||||||
// (And even if we tried to handle it, we'd also need to handle
|
|
||||||
// the case where the panic payload we get out of it also panics
|
|
||||||
// on drop, and so on. See issue #86027.)
|
|
||||||
*self.result.get_mut() = None;
|
|
||||||
// Now that there will be no more user code running on this thread
|
// Now that there will be no more user code running on this thread
|
||||||
// that can use 'scope, mark the thread as 'finished'.
|
// that can use 'scope, mark the thread as 'finished'.
|
||||||
|
// It's important we only do this after the `result` has been dropped,
|
||||||
|
// since dropping it might still use things it borrowed from 'scope.
|
||||||
scope.decrement_num_running_threads(unhandled_panic);
|
scope.decrement_num_running_threads(unhandled_panic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue