Make io::Error Sync

Currently we use a marker that contains an `UnsafeCell` but `UnsafeCell`
is not `Sync` so this makes `io::Error` not `Sync`. We can instead wrap
the `UnsafeCell` and implement `Sync` for it.

Fix: #3883
This commit is contained in:
Tobin C. Harding 2025-01-17 14:22:31 +11:00
parent 274205e147
commit 31dda6d53d
No known key found for this signature in database
GPG Key ID: 40BF9E4C269D6607
2 changed files with 17 additions and 4 deletions

View File

@ -6,10 +6,12 @@ use core::fmt;
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
/// Indicates that the `struct` can pretend to own a mutable static reference
/// and an [`UnsafeCell`](core::cell::UnsafeCell), which are not unwind safe.
/// This is so that it does not introduce non-additive cargo features.
_not_unwind_safe: core::marker::PhantomData<(&'static mut (), core::cell::UnsafeCell<()>)>,
/// We want this type to be `?UnwindSafe` and `?RefUnwindSafe` - the same as `std::io::Error`.
///
/// In `std` builds the existence of `dyn std::error:Error` prevents `UnwindSafe` and
/// `RefUnwindSafe` from being automatically implemented. But in `no-std` builds without the
/// marker nothing prevents it.
_not_unwind_safe: core::marker::PhantomData<NotUnwindSafe>,
#[cfg(feature = "std")]
error: Option<Box<dyn std::error::Error + Send + Sync + 'static>>,
@ -100,6 +102,13 @@ impl From<Error> for std::io::Error {
}
}
/// Useful for preventing `UnwindSafe` and `RefUnwindSafe` from being automatically implemented.
struct NotUnwindSafe {
_not_unwind_safe: core::marker::PhantomData<(&'static mut (), core::cell::UnsafeCell<()>)>,
}
unsafe impl Sync for NotUnwindSafe {}
macro_rules! define_errorkind {
($($(#[$($attr:tt)*])* $kind:ident),*) => {
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]

View File

@ -137,4 +137,8 @@ fn all_non_error_tyes_implement_send_sync() {
// Types are `Send` and `Sync` where possible (C-SEND-SYNC).
assert_send::<Types>();
assert_sync::<Types>();
// Error types are meaningful and well-behaved (C-GOOD-ERR)
assert_send::<Errors>();
assert_sync::<Errors>();
}