Skip to content

[derive] TryFromBytes on unions w/o Immutable #2538

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
100 changes: 54 additions & 46 deletions src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ use super::*;
//
// [1] https://doc.rust-lang.org/1.81.0/reference/type-layout.html#tuple-layout
const _: () = unsafe {
unsafe_impl!((): Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
unsafe_impl!((): Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
assert_unaligned!(());
};

Expand Down Expand Up @@ -60,25 +60,31 @@ const _: () = unsafe {
// FIXME(#278): Once we've updated the trait docs to refer to `u8`s rather than
// bits or bytes, update this comment, especially the reference to [1].
const _: () = unsafe {
unsafe_impl!(u8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
unsafe_impl!(i8: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
unsafe_impl!(u8: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
unsafe_impl!(i8: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
assert_unaligned!(u8, i8);
unsafe_impl!(u16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(i16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(u32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(i32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(u64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(i64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(u128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(i128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(usize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(isize: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(f32: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(f64: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(u16: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(i16: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(u32: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(i32: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(u64: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(i64: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(u128: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(i128: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(usize: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(isize: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(f32: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(f64: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
#[cfg(feature = "float-nightly")]
unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f16: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(
#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))]
f16: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes
);
#[cfg(feature = "float-nightly")]
unsafe_impl!(#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))] f128: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(
#[cfg_attr(doc_cfg, doc(cfg(feature = "float-nightly")))]
f128: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes
);
};

// SAFETY:
Expand Down Expand Up @@ -107,7 +113,7 @@ const _: () = unsafe {
unsafe_impl!(=> TryFromBytes for bool; |byte| {
let byte = byte.transmute::<u8, invariant::Valid, _>();
*byte.unaligned_as_ref() < 2
})
}; IS_IMMUTABLE = true)
};
impl_size_eq!(bool, u8);

Expand Down Expand Up @@ -137,7 +143,7 @@ const _: () = unsafe {
let c = c.transmute::<Unalign<u32>, invariant::Valid, _>();
let c = c.read_unaligned().into_inner();
char::from_u32(c).is_some()
});
}; IS_IMMUTABLE = true);
};

impl_size_eq!(char, Unalign<u32>);
Expand Down Expand Up @@ -170,7 +176,7 @@ const _: () = unsafe {
let c = c.transmute::<[u8], invariant::Valid, _>();
let c = c.unaligned_as_ref();
core::str::from_utf8(c).is_ok()
})
}; IS_IMMUTABLE = true)
};

// SAFETY: `str` and `[u8]` have the same layout [1].
Expand Down Expand Up @@ -210,7 +216,7 @@ macro_rules! unsafe_impl_try_from_bytes_for_nonzero {

let n = n.transmute::<Unalign<$prim>, invariant::Valid, _>();
$nonzero::new(n.read_unaligned().into_inner()).is_some()
});
}; IS_IMMUTABLE = true);
)*
}
}
Expand Down Expand Up @@ -296,19 +302,19 @@ const _: () = unsafe {
// FIXME(https://github.com/rust-lang/rust/pull/104082): Cite documentation for
// layout guarantees.
const _: () = unsafe {
unsafe_impl!(Option<NonZeroU8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
unsafe_impl!(Option<NonZeroI8>: TryFromBytes, FromZeros, FromBytes, IntoBytes, Unaligned);
unsafe_impl!(Option<NonZeroU8>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
unsafe_impl!(Option<NonZeroI8>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes, Unaligned);
assert_unaligned!(Option<NonZeroU8>, Option<NonZeroI8>);
unsafe_impl!(Option<NonZeroU16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroI16>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroU32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroI32>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroU64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroI64>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroU128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroI128>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroUsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroIsize>: TryFromBytes, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroU16>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroI16>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroU32>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroI32>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroU64>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroI64>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroU128>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroI128>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroUsize>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
unsafe_impl!(Option<NonZeroIsize>: TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes);
};

// SAFETY: While it's not fully documented, the consensus is that `Box<T>` does
Expand Down Expand Up @@ -348,34 +354,34 @@ const _: () = unsafe {
#[cfg(feature = "alloc")]
unsafe_impl!(
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c)
T => TryFromBytes for Option<Box<T>>; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true
);
#[cfg(feature = "alloc")]
unsafe_impl!(
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
T => FromZeros for Option<Box<T>>
);
unsafe_impl!(
T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c)
T => TryFromBytes for Option<&'_ T>; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true
);
unsafe_impl!(T => FromZeros for Option<&'_ T>);
unsafe_impl!(
T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c)
T => TryFromBytes for Option<&'_ mut T>; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true
);
unsafe_impl!(T => FromZeros for Option<&'_ mut T>);
unsafe_impl!(
T => TryFromBytes for Option<NonNull<T>>; |c| pointer::is_zeroed(c)
T => TryFromBytes for Option<NonNull<T>>; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true
);
unsafe_impl!(T => FromZeros for Option<NonNull<T>>);
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_fn!(...));
unsafe_impl_for_power_set!(
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_fn!(...);
|c| pointer::is_zeroed(c)
|c| pointer::is_zeroed(c); IS_IMMUTABLE = true
);
unsafe_impl_for_power_set!(A, B, C, D, E, F, G, H, I, J, K, L -> M => FromZeros for opt_extern_c_fn!(...));
unsafe_impl_for_power_set!(
A, B, C, D, E, F, G, H, I, J, K, L -> M => TryFromBytes for opt_extern_c_fn!(...);
|c| pointer::is_zeroed(c)
|c| pointer::is_zeroed(c); IS_IMMUTABLE = true
);
};

Expand Down Expand Up @@ -679,7 +685,7 @@ mod atomics {
// [1] https://doc.rust-lang.org/1.81.0/std/marker/struct.PhantomData.html#layout-1
const _: () = unsafe {
unsafe_impl!(T: ?Sized => Immutable for PhantomData<T>);
unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData<T>);
unsafe_impl!(T: ?Sized => TryFromBytes for PhantomData<T>; IS_IMMUTABLE = true);
unsafe_impl!(T: ?Sized => FromZeros for PhantomData<T>);
unsafe_impl!(T: ?Sized => FromBytes for PhantomData<T>);
unsafe_impl!(T: ?Sized => IntoBytes for PhantomData<T>);
Expand Down Expand Up @@ -712,7 +718,7 @@ const _: () = unsafe { unsafe_impl!(T: Unaligned => Unaligned for Wrapping<T>) }
// SAFETY: `TryFromBytes` (with no validator), `FromZeros`, `FromBytes`:
// `MaybeUninit<T>` has no restrictions on its contents.
const _: () = unsafe {
unsafe_impl!(T => TryFromBytes for CoreMaybeUninit<T>);
unsafe_impl!(T => TryFromBytes for CoreMaybeUninit<T>; IS_IMMUTABLE = T::IS_IMMUTABLE);
unsafe_impl!(T => FromZeros for CoreMaybeUninit<T>);
unsafe_impl!(T => FromBytes for CoreMaybeUninit<T>);
};
Expand Down Expand Up @@ -808,6 +814,8 @@ unsafe impl<T: TryFromBytes + ?Sized> TryFromBytes for UnsafeCell<T> {
{
}

const IS_IMMUTABLE: bool = false;

#[inline]
fn is_bit_valid<A: invariant::Reference>(candidate: Maybe<'_, Self, A>) -> bool {
// The only way to implement this function is using an exclusive-aliased
Expand Down Expand Up @@ -864,7 +872,7 @@ const _: () = unsafe {
// it explicitly warns that it's a possibility), and we have not
// violated any safety invariants that we must fix before returning.
<[T] as TryFromBytes>::is_bit_valid(c.as_slice())
});
}; IS_IMMUTABLE = T::IS_IMMUTABLE);
unsafe_impl!(const N: usize, T: FromZeros => FromZeros for [T; N]);
unsafe_impl!(const N: usize, T: FromBytes => FromBytes for [T; N]);
unsafe_impl!(const N: usize, T: IntoBytes => IntoBytes for [T; N]);
Expand Down Expand Up @@ -893,7 +901,7 @@ const _: () = unsafe {
// we have not violated any safety invariants that we must fix before
// returning.
c.iter().all(<T as TryFromBytes>::is_bit_valid)
});
}; IS_IMMUTABLE = T::IS_IMMUTABLE);
unsafe_impl!(T: FromZeros => FromZeros for [T]);
unsafe_impl!(T: FromBytes => FromBytes for [T]);
unsafe_impl!(T: IntoBytes => IntoBytes for [T]);
Expand All @@ -919,9 +927,9 @@ const _: () = unsafe {
const _: () = unsafe {
unsafe_impl!(T: ?Sized => Immutable for *const T);
unsafe_impl!(T: ?Sized => Immutable for *mut T);
unsafe_impl!(T => TryFromBytes for *const T; |c| pointer::is_zeroed(c));
unsafe_impl!(T => TryFromBytes for *const T; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true);
unsafe_impl!(T => FromZeros for *const T);
unsafe_impl!(T => TryFromBytes for *mut T; |c| pointer::is_zeroed(c));
unsafe_impl!(T => TryFromBytes for *mut T; |c| pointer::is_zeroed(c); IS_IMMUTABLE = true);
unsafe_impl!(T => FromZeros for *mut T);
};

Expand Down Expand Up @@ -1032,7 +1040,7 @@ mod simd {
impl_known_layout!($($typ),*);
// SAFETY: See comment on module definition for justification.
const _: () = unsafe {
$( unsafe_impl!($typ: Immutable, TryFromBytes, FromZeros, FromBytes, IntoBytes); )*
$( unsafe_impl!($typ: Immutable, TryFromBytes; IS_IMMUTABLE = true, FromZeros, FromBytes, IntoBytes); )*
};
}
};
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1448,6 +1448,9 @@ pub unsafe trait TryFromBytes {
where
Self: Sized;

#[doc(hidden)]
const IS_IMMUTABLE: bool;

/// Does a given memory range contain a valid instance of `Self`?
///
/// # Safety
Expand Down
8 changes: 8 additions & 0 deletions src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,10 @@ macro_rules! cryptocorrosion_derive_traits {
$($field_ty: $crate::FromBytes,)*
)?
{
const IS_IMMUTABLE: bool = true $(
&& <$field_ty as $crate::TryFromBytes>::IS_IMMUTABLE
)*;

fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool
where
A: $crate::pointer::invariant::Reference
Expand Down Expand Up @@ -923,6 +927,10 @@ macro_rules! cryptocorrosion_derive_traits {
$field_ty: $crate::FromBytes,
)*
{
const IS_IMMUTABLE: bool = true $(
&& <$field_ty as $crate::TryFromBytes>::IS_IMMUTABLE
)*;

fn is_bit_valid<A>(_c: $crate::Maybe<'_, Self, A>) -> bool
where
A: $crate::pointer::invariant::Reference
Expand Down
Loading
Loading