diff --git a/futures-channel/src/mpsc/mod.rs b/futures-channel/src/mpsc/mod.rs index d026bd1b9..5222f5bb1 100644 --- a/futures-channel/src/mpsc/mod.rs +++ b/futures-channel/src/mpsc/mod.rs @@ -82,6 +82,7 @@ use futures_core::stream::{FusedStream, Stream}; use futures_core::task::__internal::AtomicWaker; use futures_core::task::{Context, Poll, Waker}; use std::fmt; +use std::panic::{RefUnwindSafe, UnwindSafe}; use std::pin::Pin; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::SeqCst; @@ -147,6 +148,35 @@ pub struct UnboundedReceiver { // `Pin<&mut UnboundedReceiver>` is never projected to `Pin<&mut T>` impl Unpin for UnboundedReceiver {} +// The `UnwindSafe` trait is not easy to reason about. Rather than demonstrate +// why `UnwindSafe` is required on `T`, it is easier to give counter-examples +// where unwind safety would be broken without this requirement. +// For the `Receiver`, a counter-example is trivial: without the trait bound +// requirement, one could pass a `Receiver` through the `catch_unwind` +// boundary then send a non-`UnwindSafe` trait to it from the outside. +// For the `Sender`, a counter-example is: +// let (tx, rx) = channel::>>(); +// catch_unwind(|| { +// let a = Arc::new(RefCell::new(...)); +// tx.send(a.clone()); +// a.borrow_mut().half_modification(); +// panic!(); +// }) +// let a = rx.recv().unwrap(); // `a` is in a corrupted state. +impl UnwindSafe for UnboundedReceiver {} +impl UnwindSafe for UnboundedSender {} +impl UnwindSafe for Receiver {} +impl UnwindSafe for Sender {} +// There's nothing the API user can do with a `&Sender` or `&Receiver`. +// They act as a potential container for a `T` and are thus similar to, say, +// a `Box` for unwind-safety-related purposes. If it was possible to +// send/receive items through a `&Sender` or `&Receiver`, then this would +// require `T: UnwindSafe` instead. +impl RefUnwindSafe for UnboundedReceiver {} +impl RefUnwindSafe for UnboundedSender {} +impl RefUnwindSafe for Receiver {} +impl RefUnwindSafe for Sender {} + /// The error type for [`Sender`s](Sender) used as `Sink`s. #[derive(Clone, Debug, PartialEq, Eq)] pub struct SendError { diff --git a/futures-channel/src/oneshot.rs b/futures-channel/src/oneshot.rs index fe5b115a3..2b50cfeb3 100644 --- a/futures-channel/src/oneshot.rs +++ b/futures-channel/src/oneshot.rs @@ -4,6 +4,7 @@ use alloc::sync::Arc; use core::fmt; +use core::panic::{RefUnwindSafe, UnwindSafe}; use core::pin::Pin; use core::sync::atomic::AtomicBool; use core::sync::atomic::Ordering::SeqCst; @@ -31,6 +32,31 @@ pub struct Sender { impl Unpin for Receiver {} impl Unpin for Sender {} +// The `UnwindSafe` trait is not easy to reason about. Rather than demonstrate +// why `UnwindSafe` is required on `T`, it is easier to give counter-examples +// where unwind safety would be broken without this requirement. +// For the `Receiver`, a counter-example is trivial: without the trait bound +// requirement, one could pass a `Receiver` through the `catch_unwind` +// boundary then send a non-`UnwindSafe` trait to it from the outside. +// For the `Sender`, a counter-example is: +// let (tx, rx) = channel::>>(); +// catch_unwind(|| { +// let a = Arc::new(RefCell::new(...)); +// tx.send(a.clone()); +// a.borrow_mut().half_modification(); +// panic!(); +// }) +// let a = rx.recv().unwrap(); // `a` is in a corrupted state. +impl UnwindSafe for Receiver {} +impl UnwindSafe for Sender {} +// There's nothing the API user can do with a `&Sender` or `&Receiver`. +// They act as a potential container for a `T` and are thus similar to, say, +// a `Box` for unwind-safety-related purposes. If it was possible to +// send/receive items through a `&Sender` or `&Receiver`, then this would +// require `T: UnwindSafe` instead. +impl RefUnwindSafe for Receiver {} +impl RefUnwindSafe for Sender {} + /// Internal state of the `Receiver`/`Sender` pair above. This is all used as /// the internal synchronization between the two for send/recv operations. struct Inner {