Skip to content

Commit

Permalink
runtime: swallow panics in drop(join_handle)
Browse files Browse the repository at this point in the history
fixes tokio-rs#4412

From the issue description:

> In Tokio, panics are generally caught and not passed resumed when
dropping the JoinHandle, however when dropping the JoinHandle of a task
that has already completed, that panic can propagate to the user who
dropped the JoinHandle.

This PR fixes that.
  • Loading branch information
BraulioVM committed Jan 27, 2022
1 parent 257053e commit deeb4a2
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 11 deletions.
12 changes: 1 addition & 11 deletions tokio/src/runtime/task/harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -175,21 +173,13 @@ 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(|| {
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.
Expand Down
20 changes: 20 additions & 0 deletions tokio/tests/join_handle_panic.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit deeb4a2

Please sign in to comment.