Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions compio-executor/src/task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ impl<F: Future + 'static> TaskAlloc<F> {
}

unsafe fn drop_future(header: NonNull<Header>, has_result: bool) {
// The future/result types are unwind-unsafe (ManuallyDrop, union).
// Dropping them during an existing panic could trigger a second panic,
// which would be UB. Instead, leak the contents during unwinding.
if ::std::thread::panicking() {
return;
}

let future_cell = Self::future_cell(header);

future_cell.with_mut(|fut_ptr| {
Expand Down Expand Up @@ -298,6 +305,13 @@ impl Task {

header.shared.store(ptr::null_mut(), Release);

// Dropping the future/result and waker during unwinding on unwind-unsafe
// types could trigger a second panic. Skip content drops if already panicking.
if ::std::thread::panicking() {
trace!("Skipping content drops during panic");
return;
}

if !state.is_completed() {
trace!("Dropping future");
// The task has not completed yet, drop future
Expand Down Expand Up @@ -361,6 +375,16 @@ impl Drop for Task {
return;
};

// The future/result and waker types are unwind-unsafe (ManuallyDrop in
// union, MaybeUninit). Dropping them during an existing panic could
// trigger a second panic, which would be UB. Skip content drops but
// still deallocate the memory since dealloc does not run destructors
// on the inner types.
if ::std::thread::panicking() {
unsafe { (header.vtable.dealloc)(self.0) }
return;
}

crate::panic_guard!();

debug_assert!(state.is_completed() | state.is_cancelled());
Expand Down
16 changes: 16 additions & 0 deletions compio-runtime/tests/panic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::time::Duration;

use compio_runtime::time::sleep;

#[test]
#[should_panic]
fn panic_spawn() {
compio_runtime::Runtime::new().unwrap().block_on(async {
let _handle = compio_runtime::spawn(async {
sleep(Duration::from_millis(100)).await;
panic!("test panic in spawn");
});
sleep(Duration::from_millis(100)).await;
panic!("another panic");
})
}
Loading