Question: why is delay not unwind safe?
xmclark opened this issue · comments
A fairly minimal example:
use std::time::Duration;
use futures::FutureExt;
#[runtime::main]
async fn main() {
let _ = runtime::time::Delay::new(Duration::from_millis(100)).catch_unwind().await;
}
Output:
error[E0277]: the type `(dyn runtime_raw::time::Delay<Output = std::time::Instant> + 'static)` may not be safely transferred across an unwind boundary
I can mitigate the problem by wrapping the future in AssertUnwindSafe
but that is a smell to me and I don't understand the consequences of doing that. Still trying to wrap my head around the new async syntax and unwind stuff.
I think I was able to answer my own question:
The Pin<Box<dyn Delay>>>
was hiding more interesting error messages. With a small change to the example: awaiting the underlying futures_timer::Delay
reveals a reference to an AtomicWaker
which is !RefUnwindSafe
due to an UnsafeCell
. Because a contained type is UnwindSafe, so is runtime Delay.
use std::time::Duration;
use futures::FutureExt;
use futures_timer::{Delay as AsyncDelay};
#[runtime::main]
async fn main() {
AsyncDelay::new(Duration::from_millis(100)).catch_unwind().await;
}
error:
error[E0277]: the type `std::cell::UnsafeCell<std::option::Option<std::task::Waker>>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
--> src/main.rs:8:49
|
8 | AsyncDelay::new(Duration::from_millis(100)).catch_unwind().await;
| ^^^^^^^^^^^^ `std::cell::UnsafeCell<std::option::Option<std::task::Waker>>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
|
= help: within `futures_timer::arc_list::Node<futures_timer::ScheduledTimer>`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell<std::option::Option<std::task::Waker>>`
= note: required because it appears within the type `futures_core::task::__internal::atomic_waker::AtomicWaker`
= note: required because it appears within the type `futures_timer::ScheduledTimer`
= note: required because it appears within the type `futures_timer::arc_list::Node<futures_timer::ScheduledTimer>`
= note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::sync::Arc<futures_timer::arc_list::Node<futures_timer::ScheduledTimer>>`
= note: required because it appears within the type `std::option::Option<std::sync::Arc<futures_timer::arc_list::Node<futures_timer::ScheduledTimer>>>`
= note: required because it appears within the type `futures_timer::delay::Delay`