diff --git a/tokio/src/runtime/task/harness.rs b/tokio/src/runtime/task/harness.rs index 0996e5232db..530e6b13c54 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 00000000000..f7de92d4178 --- /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); +}