From 111dd66f3edc29d473c4741fa8829c123a70acb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Braulio=20Valdivielso=20Mart=C3=ADnez?= Date: Fri, 28 Jan 2022 16:21:03 +0000 Subject: [PATCH] runtime: swallow panics in `drop(JoinHandle)` (#4430) --- tokio/src/runtime/task/harness.rs | 16 +++++----------- tokio/tests/join_handle_panic.rs | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 tokio/tests/join_handle_panic.rs diff --git a/tokio/src/runtime/task/harness.rs b/tokio/src/runtime/task/harness.rs index 0996e5232..530e6b13c 100644 --- a/tokio/src/runtime/task/harness.rs +++ b/tokio/src/runtime/task/harness.rs @@ -165,8 +165,6 @@ where } pub(super) fn drop_join_handle_slow(self) { - let mut maybe_panic = None; - // Try to unset `JOIN_INTEREST`. This must be done as a first step in // case the task concurrently completed. if self.header().state.unset_join_interested().is_err() { @@ -175,21 +173,17 @@ where // the scheduler or `JoinHandle`. i.e. if the output remains in the // task structure until the task is deallocated, it may be dropped // by a Waker on any arbitrary thread. - let panic = panic::catch_unwind(panic::AssertUnwindSafe(|| { + // + // Panics are delivered to the user via the `JoinHandle`. Given that + // they are dropping the `JoinHandle`, we assume they are not + // interested in the panic and swallow it. + let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| { self.core().stage.drop_future_or_output(); })); - - if let Err(panic) = panic { - maybe_panic = Some(panic); - } } // Drop the `JoinHandle` reference, possibly deallocating the task self.drop_reference(); - - if let Some(panic) = maybe_panic { - panic::resume_unwind(panic); - } } /// Remotely aborts the task. diff --git a/tokio/tests/join_handle_panic.rs b/tokio/tests/join_handle_panic.rs new file mode 100644 index 000000000..f7de92d41 --- /dev/null +++ b/tokio/tests/join_handle_panic.rs @@ -0,0 +1,20 @@ +#![warn(rust_2018_idioms)] +#![cfg(feature = "full")] + +struct PanicsOnDrop; + +impl Drop for PanicsOnDrop { + fn drop(&mut self) { + panic!("I told you so"); + } +} + +#[tokio::test] +async fn test_panics_do_not_propagate_when_dropping_join_handle() { + let join_handle = tokio::spawn(async move { PanicsOnDrop }); + + // only drop the JoinHandle when the task has completed + // (which is difficult to synchronize precisely) + tokio::time::sleep(std::time::Duration::from_millis(3)).await; + drop(join_handle); +}