diff --git a/src/impls.rs b/src/impls.rs index e9c45732f2..45b5d62f1e 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -417,13 +417,14 @@ mod atomics { use super::*; macro_rules! impl_traits_for_atomics { - ($($atomics:ident),* $(,)?) => { + ($($atomics:ident [$primitives:ident]),* $(,)?) => { $( + impl_size_eq!($atomics, $primitives); impl_known_layout!($atomics); - impl_for_transparent_wrapper!(=> TryFromBytes for $atomics); - impl_for_transparent_wrapper!(=> FromZeros for $atomics); - impl_for_transparent_wrapper!(=> FromBytes for $atomics); - impl_for_transparent_wrapper!(=> IntoBytes for $atomics); + impl_for_transmute_from!(=> TryFromBytes for $atomics [UnsafeCell<$primitives>]); + impl_for_transparent_wrapper!(=> FromZeros for $atomics [UnsafeCell<$primitives>]); + impl_for_transparent_wrapper!(=> FromBytes for $atomics [UnsafeCell<$primitives>]); + impl_for_transparent_wrapper!(=> IntoBytes for $atomics [UnsafeCell<$primitives>]); )* }; } @@ -435,13 +436,14 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU8, AtomicI8); + impl_traits_for_atomics!(AtomicU8[u8], AtomicI8[i8]); + impl_size_eq!(AtomicBool, bool); impl_known_layout!(AtomicBool); - impl_for_transparent_wrapper!(=> TryFromBytes for AtomicBool); - impl_for_transparent_wrapper!(=> FromZeros for AtomicBool); - impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool); + impl_for_transmute_from!(=> TryFromBytes for AtomicBool [UnsafeCell]); + impl_for_transparent_wrapper!(=> FromZeros for AtomicBool [UnsafeCell]); + impl_for_transparent_wrapper!(=> IntoBytes for AtomicBool [UnsafeCell]); safety_comment! { /// SAFETY: @@ -468,10 +470,8 @@ mod atomics { unsafe_impl!(AtomicI8: Unaligned); assert_unaligned!(AtomicBool, AtomicU8, AtomicI8); - /// SAFETY: - /// All of these pass an atomic type and that type's native equivalent, as - /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]); + /// SAFETY: TODO + unsafe_impl_transmute_from_for_atomic!(AtomicU8 [u8], AtomicI8 [i8], AtomicBool [bool]); } } @@ -482,13 +482,11 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU16, AtomicI16); + impl_traits_for_atomics!(AtomicU16[u16], AtomicI16[i16]); safety_comment! { - /// SAFETY: - /// All of these pass an atomic type and that type's native equivalent, as - /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]); + /// SAFETY: TODO + unsafe_impl_transmute_from_for_atomic!(AtomicU16 [u16], AtomicI16 [i16]); } } @@ -499,13 +497,11 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU32, AtomicI32); + impl_traits_for_atomics!(AtomicU32[u32], AtomicI32[i32]); safety_comment! { - /// SAFETY: - /// All of these pass an atomic type and that type's native equivalent, as - /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]); + /// SAFETY: TODO + unsafe_impl_transmute_from_for_atomic!(AtomicU32 [u32], AtomicI32 [i32]); } } @@ -516,13 +512,11 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicU64, AtomicI64); + impl_traits_for_atomics!(AtomicU64[u64], AtomicI64[i64]); safety_comment! { - /// SAFETY: - /// All of these pass an atomic type and that type's native equivalent, as - /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]); + /// SAFETY: TODO + unsafe_impl_transmute_from_for_atomic!(AtomicU64 [u64], AtomicI64 [i64]); } } @@ -533,21 +527,27 @@ mod atomics { use super::*; - impl_traits_for_atomics!(AtomicUsize, AtomicIsize); + impl_traits_for_atomics!(AtomicUsize[usize], AtomicIsize[isize]); impl_known_layout!(T => AtomicPtr); + // SAFETY: `AtomicPtr` and `*mut T` have the same size [1]. + // + // [1] Per https://doc.rust-lang.org/1.85.0/std/sync/atomic/struct.AtomicPtr.html: + // + // This type has the same size and bit validity as a `*mut T`. + unsafe impl crate::pointer::SizeEq<*mut T> for AtomicPtr {} + // SAFETY: See previous safety comment. + unsafe impl crate::pointer::SizeEq> for *mut T {} + // TODO(#170): Implement `FromBytes` and `IntoBytes` once we implement // those traits for `*mut T`. - impl_for_transparent_wrapper!(T => TryFromBytes for AtomicPtr); - impl_for_transparent_wrapper!(T => FromZeros for AtomicPtr); + impl_for_transmute_from!(T => TryFromBytes for AtomicPtr [UnsafeCell<*mut T>]); safety_comment! { - /// SAFETY: - /// This passes an atomic type and that type's native equivalent, as - /// required by the macro safety preconditions. - unsafe_impl_transparent_wrapper_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]); - unsafe_impl_transparent_wrapper_for_atomic!(T => AtomicPtr [*mut T]); + /// SAFETY: TODO + unsafe_impl_transmute_from_for_atomic!(AtomicUsize [usize], AtomicIsize [isize]); + unsafe_impl_transmute_from_for_atomic!(T => AtomicPtr [*mut T]); } } } @@ -577,12 +577,12 @@ safety_comment! { assert_unaligned!(PhantomData<()>, PhantomData, PhantomData); } -impl_for_transparent_wrapper!(T: Immutable => Immutable for Wrapping); -impl_for_transparent_wrapper!(T: TryFromBytes => TryFromBytes for Wrapping); -impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping); -impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping); -impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping); -impl_for_transparent_wrapper!(T: Unaligned => Unaligned for Wrapping); +unsafe_impl!(T: Immutable => Immutable for Wrapping); +impl_for_transmute_from!(T: TryFromBytes => TryFromBytes for Wrapping[T]); +impl_for_transparent_wrapper!(T: FromZeros => FromZeros for Wrapping[T]); +impl_for_transparent_wrapper!(T: FromBytes => FromBytes for Wrapping[T]); +impl_for_transparent_wrapper!(T: IntoBytes => IntoBytes for Wrapping[T]); +unsafe_impl!(T: Unaligned => Unaligned for Wrapping); assert_unaligned!(Wrapping<()>, Wrapping); safety_comment! { @@ -594,22 +594,52 @@ safety_comment! { unsafe_impl!(T => FromBytes for CoreMaybeUninit); } -impl_for_transparent_wrapper!(T: Immutable => Immutable for CoreMaybeUninit); -impl_for_transparent_wrapper!(T: Unaligned => Unaligned for CoreMaybeUninit); +unsafe_impl!(T: Immutable => Immutable for CoreMaybeUninit); +unsafe_impl!(T: Unaligned => Unaligned for CoreMaybeUninit); assert_unaligned!(CoreMaybeUninit<()>, CoreMaybeUninit); -impl_for_transparent_wrapper!(T: ?Sized + Immutable => Immutable for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + TryFromBytes => TryFromBytes for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop); +unsafe_impl!(T: ?Sized + Immutable => Immutable for ManuallyDrop); + +// SAFETY: See inline safety comment justifying that the implementation of +// `is_bit_valid`is sound. +unsafe impl TryFromBytes for ManuallyDrop { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + + #[inline(always)] + fn is_bit_valid( + candidate: Maybe<'_, Self, A>, + ) -> bool { + // SAFETY: `ManuallyDrop` and `T` have the same size [1], so this + // cast preserves size. It also preserves provenance. + // + // [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T` + let c: Maybe<'_, T, A> = unsafe { candidate.cast_unsized(|p| cast!(p => NonNull<_>)) }; + + // SAFETY: `ManuallyDrop` and `T` have the same bit validity [1], so + // this is a sound implementation of `ManuallyDrop::is_bit_valid`. + // + // [1] Per https://doc.rust-lang.org/1.85.0/std/mem/struct.ManuallyDrop.html: + // + // `ManuallyDrop` is guaranteed to have the same layout and bit + // validity as `T` + ::is_bit_valid(c) + } +} + +impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for ManuallyDrop[T]); +impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for ManuallyDrop[T]); +impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for ManuallyDrop[T]); +unsafe_impl!(T: ?Sized + Unaligned => Unaligned for ManuallyDrop); assert_unaligned!(ManuallyDrop<()>, ManuallyDrop); -impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell); -impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell); -impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell); -impl_for_transparent_wrapper!(T: ?Sized + Unaligned => Unaligned for UnsafeCell); +impl_for_transparent_wrapper!(T: ?Sized + FromZeros => FromZeros for UnsafeCell[T]); +impl_for_transparent_wrapper!(T: ?Sized + FromBytes => FromBytes for UnsafeCell[T]); +impl_for_transparent_wrapper!(T: ?Sized + IntoBytes => IntoBytes for UnsafeCell[T]); +unsafe_impl!(T: ?Sized + Unaligned => Unaligned for UnsafeCell); assert_unaligned!(UnsafeCell<()>, UnsafeCell); // SAFETY: See safety comment in `is_bit_valid` impl. diff --git a/src/lib.rs b/src/lib.rs index 71193d661b..567fa85716 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -805,6 +805,14 @@ pub unsafe trait KnownLayout { // resulting size would not fit in a `usize`. meta.size_for_metadata(Self::LAYOUT) } + + fn cast_from_raw + ?Sized>( + ptr: NonNull

, + ) -> NonNull { + let data = ptr.cast::(); + let meta = P::pointer_to_metadata(ptr.as_ptr()); + Self::raw_from_ptr_len(data, meta) + } } /// The metadata associated with a [`KnownLayout`] type. @@ -2843,15 +2851,15 @@ unsafe fn try_read_from( // We use `from_mut` despite not mutating via `c_ptr` so that we don't need // to add a `T: Immutable` bound. let c_ptr = Ptr::from_mut(&mut candidate); - let c_ptr = c_ptr.transparent_wrapper_into_inner(); // SAFETY: `c_ptr` has no uninitialized sub-ranges because it derived from // `candidate`, which the caller promises is entirely initialized. Since // `candidate` is a `MaybeUninit`, it has no validity requirements, and so - // no values written to `c_ptr` can violate its validity. Since `c_ptr` has - // `Exclusive` aliasing, no mutations may happen except via `c_ptr` so long - // as it is live, so we don't need to worry about the fact that `c_ptr` may - // have more restricted validity than `candidate`. + // no values written to an `Initialized` `c_ptr` can violate its validity. + // Since `c_ptr` has `Exclusive` aliasing, no mutations may happen except + // via `c_ptr` so long as it is live, so we don't need to worry about the + // fact that `c_ptr` may have more restricted validity than `candidate`. let c_ptr = unsafe { c_ptr.assume_validity::() }; + let c_ptr = c_ptr.transmute(); // This call may panic. If that happens, it doesn't cause any soundness // issues, as we have not generated any invalid state which we need to @@ -2861,7 +2869,7 @@ unsafe fn try_read_from( // calling `try_into_valid` (and thus `is_bit_valid`) with a shared // pointer when `Self: !Immutable`. Since `Self: Immutable`, this panic // condition will not happen. - if !T::is_bit_valid(c_ptr.forget_aligned()) { + if !util::SizedKnownLayout::::is_bit_valid(c_ptr.forget_aligned()) { return Err(ValidityError::new(source).into()); } @@ -4258,7 +4266,9 @@ pub unsafe trait FromBytes: FromZeros { let source = Ptr::from_mut(source); let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); match maybe_slf { - Ok(slf) => Ok(slf.bikeshed_recall_valid().as_mut()), + Ok(slf) => Ok(slf + .bikeshed_recall_valid::<(_, (_, (BecauseExclusive, BecauseExclusive)))>() + .as_mut()), Err(err) => Err(err.map_src(|s| s.as_mut())), } } @@ -4728,7 +4738,7 @@ fn ref_from_prefix_suffix( /// If there are insufficient bytes, or if that affix of `source` is not /// appropriately aligned, this returns `Err`. #[inline(always)] -fn mut_from_prefix_suffix( +fn mut_from_prefix_suffix( source: &mut [u8], meta: Option, cast_type: CastType, diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index d2bc8727ab..dfcf59e7de 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -12,11 +12,15 @@ mod inner; #[doc(hidden)] pub mod invariant; mod ptr; +mod transmute; #[doc(hidden)] -pub use invariant::{BecauseExclusive, BecauseImmutable, Read}; +pub(crate) use transmute::*; #[doc(hidden)] -pub use ptr::Ptr; +pub use { + invariant::{BecauseExclusive, BecauseImmutable, Read}, + ptr::Ptr, +}; use crate::Unaligned; diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index a3d487ce54..989611562a 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -12,9 +12,12 @@ use core::{ ptr::NonNull, }; -use super::{inner::PtrInner, invariant::*}; use crate::{ - util::{AlignmentVariance, Covariant, TransparentWrapper, ValidityVariance}, + pointer::{ + inner::PtrInner, + invariant::*, + transmute::{Foo, TransmuteFromPtr}, + }, AlignmentError, CastError, CastType, KnownLayout, SizeError, TryFromBytes, ValidityError, }; @@ -383,53 +386,31 @@ mod _conversions { } } - /// `Ptr<'a, T = Wrapper>` → `Ptr<'a, U>` - impl<'a, T, I> Ptr<'a, T, I> - where - T: 'a + TransparentWrapper + ?Sized, - I: Invariants, - { - /// Converts `self` to a transparent wrapper type into a `Ptr` to the - /// wrapped inner type. - pub(crate) fn transparent_wrapper_into_inner( - self, - ) -> Ptr< - 'a, - T::Inner, - ( - I::Aliasing, - >::Applied, - >::Applied, - ), - > { - // SAFETY: - // - By invariant on `TransparentWrapper::cast_into_inner`: - // - This cast preserves address and referent size, and thus the - // returned pointer addresses the same bytes as `p` - // - This cast preserves provenance - // - By invariant on `TransparentWrapper`, `T` and `T::Inner` have `UnsafeCell`s at the same - // byte ranges. Since `p` and the returned pointer address the - // same byte range, they refer to `UnsafeCell`s at the same byte - // ranges. - // - By invariant on `TransparentWrapper`, since `self` satisfies - // the validity invariant `I::Validity`, the returned pointer (of - // type `T::Inner`) satisfies the given "applied" validity - // invariant. - let ptr = unsafe { self.transmute_unchecked(|p| T::cast_into_inner(p)) }; - // SAFETY: By invariant on `TransparentWrapper`, since `self` - // satisfies the alignment invariant `I::Alignment`, the returned - // pointer (of type `T::Inner`) satisfies the given "applied" - // alignment invariant. - unsafe { ptr.assume_alignment() } - } - } - /// `Ptr<'a, T>` → `Ptr<'a, U>` impl<'a, T: ?Sized, I> Ptr<'a, T, I> where I: Invariants, { + pub(crate) fn transmute(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)> + where + T: KnownLayout, + V: Validity, + U: TransmuteFromPtr + + KnownLayout + + ?Sized, + { + unsafe { self.transmute_unchecked(|t: NonNull| U::cast_from_raw(t)) } + } + + pub(crate) fn transmute_sized(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)> + where + T: Sized, + V: Validity, + U: TransmuteFromPtr, + { + unsafe { self.transmute_unchecked(|t: NonNull| cast!(t => NonNull)) } + } + /// Casts to a different (unsized) target type without checking interior /// mutability. /// @@ -460,14 +441,9 @@ mod _conversions { ) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)> where V: Validity, - F: FnOnce(*mut T) -> *mut U, + F: FnOnce(NonNull) -> NonNull, { - let ptr = cast(self.as_inner().as_non_null().as_ptr()); - - // SAFETY: Caller promises that `cast` returns a pointer whose - // address is in the range of `self.as_inner().as_non_null()`'s referent. By - // invariant, none of these addresses are null. - let ptr = unsafe { NonNull::new_unchecked(ptr) }; + let ptr = cast(self.as_inner().as_non_null()); // SAFETY: // @@ -552,7 +528,7 @@ mod _conversions { // validity of the other. let ptr = unsafe { #[allow(clippy::as_conversions)] - self.transmute_unchecked(|p: *mut T| p as *mut crate::Unalign) + self.transmute_unchecked(NonNull::cast::>) }; ptr.bikeshed_recall_aligned() } @@ -561,6 +537,8 @@ mod _conversions { /// State transitions between invariants. mod _transitions { + use crate::pointer::transmute::TryTransmuteFromPtr; + use super::*; impl<'a, T, I> Ptr<'a, T, I> @@ -819,14 +797,11 @@ mod _transitions { #[inline] // TODO(#859): Reconsider the name of this method before making it // public. - pub fn bikeshed_recall_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> + pub fn bikeshed_recall_valid(self) -> Ptr<'a, T, (I::Aliasing, I::Alignment, Valid)> where - T: crate::FromBytes, + T: crate::FromBytes + TryTransmuteFromPtr, I: Invariants, { - // TODO(#1866): Fix this unsoundness. - - // SAFETY: This is unsound! unsafe { self.assume_valid() } } @@ -843,11 +818,13 @@ mod _transitions { /// On error, unsafe code may rely on this method's returned /// `ValidityError` containing `self`. #[inline] - pub(crate) fn try_into_valid( + pub(crate) fn try_into_valid( mut self, ) -> Result, ValidityError> where - T: TryFromBytes + Read, + T: TryFromBytes + + Read + + TryTransmuteFromPtr, I::Aliasing: Reference, I: Invariants, { @@ -855,12 +832,10 @@ mod _transitions { // issues, as we have not generated any invalid state which we need to // fix before returning. if T::is_bit_valid(self.reborrow().forget_aligned()) { - // SAFETY: If `T::is_bit_valid`, code may assume that `self` - // contains a bit-valid instance of `Self`. + // TODO: Complete this safety comment. // - // TODO(#1866): This is unsound! The returned `Ptr` may permit - // writing referents which do not satisfy the `Initialized` - // validity invariant of `self`. + // If `T::is_bit_valid`, code may assume that `self` contains a + // bit-valid instance of `Self`. Ok(unsafe { self.assume_valid() }) } else { Err(ValidityError::new(self)) @@ -902,9 +877,10 @@ mod _casts { /// - `u` has the same provenance as `p` /// - If `I::Aliasing` is [`Shared`], `UnsafeCell`s in `*u` must exist /// at ranges identical to those at which `UnsafeCell`s exist in `*p` + /// TODO: UnsafeCell compatibility #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized_unchecked *mut U>( + pub(crate) unsafe fn cast_unsized_unchecked) -> NonNull>( self, cast: F, ) -> Ptr<'a, U, (I::Aliasing, Unaligned, I::Validity)> @@ -940,20 +916,29 @@ mod _casts { /// - `u` has the same provenance as `p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized( + pub unsafe fn cast_unsized( self, cast: F, ) -> Ptr<'a, U, (I::Aliasing, Unaligned, I::Validity)> where - T: Read, - U: 'a + ?Sized + Read + CastableFrom, - F: FnOnce(*mut T) -> *mut U, + T: Foo, + U: 'a + ?Sized + CastableFrom, + F: FnOnce(NonNull) -> NonNull, { - // SAFETY: Because `T` and `U` both implement `Read`, - // either: - // - `I::Aliasing` is `Exclusive` - // - `T` and `U` are both `Immutable`, in which case they trivially - // contain `UnsafeCell`s at identical locations + // SAFETY: Because `T: Foo`, one of the following + // holds: + // - `T: Read` and `U: Read`, in which + // case one of the following holds: + // - `I::Aliasing` is `Exclusive` + // - `T` and `U` are both `Immutable` + // - `T` and `U` contain `UnsafeCell`s at identical locations + // + // In the first case, `I::Aliasing` is `Exclusive`, and in the + // second and third case, `T` and `U` contain `UnsafeCell`s at + // identical locations (in the second case, this is because `T` and + // `U` contain no `UnsafeCell`s at all). + // + // TODO: This should also promise UnsafeCell compatibility // // The caller promises all other safety preconditions. unsafe { self.cast_unsized_unchecked(cast) } @@ -988,9 +973,8 @@ mod _casts { // returned pointer addresses the same bytes as `p` // - `slice_from_raw_parts_mut` and `.cast` both preserve provenance let ptr: Ptr<'a, [u8], _> = unsafe { - self.cast_unsized(|p: *mut T| { - #[allow(clippy::as_conversions)] - core::ptr::slice_from_raw_parts_mut(p.cast::(), bytes) + self.cast_unsized(|p: NonNull| { + core::ptr::NonNull::slice_from_raw_parts(p.cast::(), bytes) }) }; @@ -1214,7 +1198,7 @@ mod _casts { // inner type `T`. A consequence of this guarantee is that it is // possible to convert between `T` and `UnsafeCell`. #[allow(clippy::as_conversions)] - let ptr = unsafe { self.transmute_unchecked(|p| p as *mut T) }; + let ptr = unsafe { self.transmute_unchecked(|p| cast!(p => NonNull)) }; // SAFETY: `UnsafeCell` has the same alignment as `T` [1], // and so if `self` is guaranteed to be aligned, then so is the @@ -1321,10 +1305,12 @@ mod tests { }; // SAFETY: The bytes in `slf` must be initialized. - unsafe fn validate_and_get_len( + unsafe fn validate_and_get_len< + T: ?Sized + KnownLayout + FromBytes + Immutable, + >( slf: Ptr<'_, T, (Shared, Aligned, Initialized)>, ) -> usize { - let t = slf.bikeshed_recall_valid().as_ref(); + let t = slf.bikeshed_recall_valid::().as_ref(); let bytes = { let len = mem::size_of_val(t); diff --git a/src/pointer/transmute.rs b/src/pointer/transmute.rs new file mode 100644 index 0000000000..439b1defa9 --- /dev/null +++ b/src/pointer/transmute.rs @@ -0,0 +1,312 @@ +// Copyright 2025 The Fuchsia Authors +// +// Licensed under a BSD-style license , Apache License, Version 2.0 +// , or the MIT +// license , at your option. +// This file may not be copied, modified, or distributed except according to +// those terms. + +use core::{ + cell::UnsafeCell, + mem::{ManuallyDrop, MaybeUninit}, + num::Wrapping, +}; + +use crate::{pointer::invariant::*, FromBytes, Immutable, IntoBytes, Unalign}; + +/// # Safety +/// +/// ## Post-conditions +/// +/// Given `Dst: TryTransmuteFromPtr`, callers may assume the +/// following: +/// +/// Given `src: Ptr` where `SI: Invariants`, if the referent of `src` contains a `Dst` which conforms to the +/// validity `DV`, then it is sound to transmute `src` into `dst: Ptr` +/// whre `DI: Invariants`. +/// +/// TODO: Mention alignment +/// +/// ## Pre-conditions +/// +/// Given `src: Ptr`, `dst: Ptr`, `SI: Invariants`, and `DV: Invariants`, `Dst: +/// TryTransmuteFromPtr` is sound if all of the following +/// hold: +/// - Forwards transmutation: Any of the following hold: +/// - So long as `dst` is active, no mutation of `dst`'s referent is allowed +/// except via `dst` itself +/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid +/// `Src`s +/// - Reverse transmutation: Any of the following hold: +/// - `dst` does not permit mutation of its referent +/// - The set of `DV`-valid `Dst`s is a subset of the set of `SV`-valid +/// `Src`s +/// - Interior mutation: TODO (ie, at least one of `Exclusive` or `Immutable` +/// required) +/// +/// ## Proof +/// +/// TODO: Prove that the pre-conditions imply the post-conditions. +pub unsafe trait TryTransmuteFromPtr {} + +pub(crate) enum BecauseFoo {} + +// SAFETY: +// - Forwards transmutation: Since `Src::Inner: Read`, one of the +// following holds: +// - `Src: Immutable`, so no mutation of `dst`'s referent is permitted via +// `src`. No other references to the same referent may exist which are typed +// using `T: !Immutable`, as this would permit violating `Src: Immutable`'s +// soundness precondition. +// - Aliasing `A` is `Exclusive`, so `dst` is the only reference permitted to +// mutate its referent. +// - Reverse transmutation: Since `Src: TransmuteFrom`, `Dst`'s validity +// set is a subset of `Src`'s validity set. +// - Since `Src::Inner: Read` and `Dst::Inner: Read`, one of the following +// holds: +// - Aliasing `A` is `Exclusive`, in which case `UnsafeCell`s do not need to +// agree +// - `Src::Inner: Immutable` and `Dst::Inner: Immutable`, in which case +// `UnsafeCell`s trivially agree +unsafe impl TryTransmuteFromPtr for Dst +where + A: Aliasing, + SV: Validity, + DV: Validity, + Src: TransmuteFrom + ?Sized, + Dst: Foo + ?Sized, +{ +} + +unsafe impl TryTransmuteFromPtr for Dst +where + SV: Validity, + DV: Validity, + Src: Immutable + ?Sized, + Dst: Immutable + ?Sized, +{ +} + +/// - T: Read *and* U: Read +/// - `UnsafeCell` agreement *and* something about semantics +pub unsafe trait Foo {} + +pub(crate) enum BecauseRead {} + +unsafe impl Foo for U +where + T: Read, + U: Read, +{ +} + +pub(crate) enum BecauseUnsafeCellCompatible {} + +unsafe impl Foo for Wrapping {} + +unsafe impl Foo, A, BecauseUnsafeCellCompatible> for T {} + +unsafe impl Foo for Unalign {} + +unsafe impl Foo, A, BecauseUnsafeCellCompatible> for T {} + +unsafe impl Foo for ManuallyDrop {} + +unsafe impl Foo, A, BecauseUnsafeCellCompatible> for T {} + +pub(crate) unsafe trait TransmuteFromPtr: + TryTransmuteFromPtr + TransmuteFrom +{ +} + +unsafe impl + TransmuteFromPtr for Dst +where + Dst: TransmuteFrom + TryTransmuteFromPtr, +{ +} + +/// TODO +/// +/// # Safety +/// +/// - The set of bit patterns allowed to appear in the referent of a `Ptr` must be a subset of the set allowed to appear in the referent +/// of a `Ptr`. +/// - `Src` and `Self` must have the same size in the sense defined by +/// [`SizeEq`]. +pub(crate) unsafe trait TransmuteFrom {} + +/// # Safety +/// +/// `T` and `Self` must have the same vtable kind (`Sized`, slice DST, `dyn`, +/// etc) and have the same size. In particular: +/// - If `T: Sized` and `Self: Sized`, then their sizes must be equal +/// - If `T: ?Sized` and `Self: ?Sized`, then it must be the case that, given +/// any `t: *mut T`, `t as *mut Self` produces a pointer which addresses the +/// same number of bytes as `t`. +pub(crate) unsafe trait SizeEq {} + +// SAFETY: `T` trivially has the same size and vtable kind as `T`, and since +// pointer `*mut T -> *mut T` pointer casts are no-ops, this cast trivially +// preserves referent size (when `T: ?Sized`). +unsafe impl SizeEq for T {} + +// SAFETY: +// - Since `Src: IntoBytes`, the set of valid `Src`'s is the set of initialized +// bit patterns, which is exactly the set allowed in the referent of any +// `Initialized` `Ptr`. +// - `Src: SizeEq` +unsafe impl TransmuteFrom for Dst +where + Src: IntoBytes + ?Sized, + Dst: ?Sized, + Src: SizeEq, +{ +} + +// SAFETY: +// - Since `Dst: FromBytes`, any initialized bit pattern may appear in the +// referent of a `Ptr`. This is exactly equal to the set +// of bit patterns which may appear in the referent of any `Initialized` +// `Ptr`. +// - `Src: SizeEq` +unsafe impl TransmuteFrom for Dst +where + Src: ?Sized, + Dst: FromBytes + ?Sized, + Src: SizeEq, +{ +} + +// TODO: This seems like a smell - the soundness of this bound has nothing to do +// with `Src` or `Dst` - we're basically just saying `[u8; N]` is transmutable +// into `[u8; N]`. + +// SAFETY: +// - The set of allowed bit patterns in the referent of any `Initialized` `Ptr` +// is the same regardless of referent type. +// - `Src: SizeEq` +unsafe impl TransmuteFrom for Dst +where + Src: ?Sized, + Dst: ?Sized, + Src: SizeEq, +{ +} + +// TODO: This seems like a smell - the soundness of this bound has nothing to do +// with `Src` or `Dst` - we're basically just saying `MaybeUninit<[u8; N]>` is +// transmutable into `MaybeUninit<[u8; N]>`. + +// SAFETY: +// - A `Dst` with validity `Uninit` permits any byte sequence, and therefore can +// be transmuted from any value. +// - `Src: SizeEq` +unsafe impl TransmuteFrom for Dst +where + Src: ?Sized, + Dst: ?Sized, + V: Validity, + Src: SizeEq, +{ +} + +/// Implements `TransmuteFrom` and `SizeEq` for `T` and `$wrapper`. +/// +/// # Safety +/// +/// `T` and `$wrapper` must have the same bit validity, and must have the +/// same size in the sense of [`SizeEq`]. +macro_rules! unsafe_impl_for_transparent_wrapper { + (T $(: ?$optbound:ident)? => $wrapper:ident) => { + // SAFETY: The caller promises that `T` and `$wrapper` have the same + // bit validity. + unsafe impl TransmuteFrom for $wrapper {} + // SAFETY: See previous safety comment. + unsafe impl TransmuteFrom<$wrapper, Valid, Valid> for T {} + // SAFETY: The caller promises that `T` and `$wrapper` satisfy `SizeEq`. + unsafe impl SizeEq for $wrapper {} + // SAFETY: See previous safety comment. + unsafe impl SizeEq<$wrapper> for T {} + + // So that this macro must be invoked inside `safety_comment!` or else + // it will generate a `clippy::undocumented_unsafe_blocks` warning. + #[allow(unused_unsafe)] + const _: () = unsafe {}; + }; +} + +safety_comment! { + /// SAFETY: + /// - `ManuallyDrop` has the same size as `T` [1] + /// - `ManuallyDrop` has the same validity as `T` [1] + /// + /// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: + /// + /// `ManuallyDrop` is guaranteed to have the same layout and bit + /// validity as `T` + unsafe_impl_for_transparent_wrapper!(T: ?Sized => ManuallyDrop); + + /// SAFETY: + /// - `Unalign` promises to have the same size as `T`. + /// - `Unalign` promises to have the same validity as `T`. + unsafe_impl_for_transparent_wrapper!(T => Unalign); + + /// SAFETY: + /// - `Wrapping` has the same size as `T` [1]. + /// - `Wrapping` has only one field, which is `pub` [2]. We are also + /// guaranteed per that `Wrapping` has the same layout as `T` [1]. The + /// only way for both of these to be true simultaneously is for + /// `Wrapping` to have the same bit validity as `T`. In particular, in + /// order to change the bit validity, one of the following would need to + /// happen: + /// - `Wrapping` could change its `repr`, but this would violate the + /// layout guarantee. + /// - `Wrapping` could add or change its fields, but this would be a + /// stability-breaking change. + /// + /// [1] Per https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html#layout-1: + /// + /// `Wrapping` is guaranteed to have the same layout and ABI as `T`. + /// + /// [2] Definition from https://doc.rust-lang.org/1.85.0/core/num/struct.Wrapping.html: + /// + /// ``` + /// #[repr(transparent)] + /// pub struct Wrapping(pub T); + /// ``` + unsafe_impl_for_transparent_wrapper!(T => Wrapping); + + /// SAFETY: + /// - `Unalign` has the same size as `T` [1]. + /// - Per [1], `Unalign` has the same bit validity as `T`. Technically + /// the term "representation" doesn't guarantee this, but the subsequent + /// sentence in the documentation makes it clear that this is the + /// intention. + /// + /// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: + /// + /// `UnsafeCell` has the same in-memory representation as its inner type + /// `T`. A consequence of this guarantee is that it is possible to convert + /// between `T` and `UnsafeCell`. + unsafe_impl_for_transparent_wrapper!(T: ?Sized => UnsafeCell); +} + +// SAFETY: `MaybeUninit` has no validity requirements. Currently this is not +// explicitly guaranteed, but it's obvious from `MaybeUninit`'s documentation +// that this is the intention: +// https://doc.rust-lang.org/1.85.0/core/mem/union.MaybeUninit.html +unsafe impl TransmuteFrom for MaybeUninit {} + +// SAFETY: `MaybeUninit` has the same size as `T` [1]. +// +// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: +// +// `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as +// `T` +unsafe impl SizeEq for MaybeUninit {} +// SAFETY: See previous safety comment. +unsafe impl SizeEq> for T {} diff --git a/src/ref.rs b/src/ref.rs index 0f4ce00214..e35d8572b2 100644 --- a/src/ref.rs +++ b/src/ref.rs @@ -799,7 +799,7 @@ where let ptr = Ptr::from_mut(b.deref_mut()) .try_cast_into_no_leftover::(None) .expect("zerocopy internal error: DerefMut::deref_mut should be infallible"); - let ptr = ptr.bikeshed_recall_valid(); + let ptr = ptr.bikeshed_recall_valid::<(_, (_, (BecauseExclusive, BecauseExclusive)))>(); ptr.as_mut() } } diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 7db924fb59..5799001399 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -17,15 +17,21 @@ #![allow(missing_debug_implementations)] -use core::mem::{self, ManuallyDrop}; +use core::{ + mem::{self, ManuallyDrop}, + ptr::NonNull, +}; // TODO(#29), TODO(https://github.com/rust-lang/rust/issues/69835): Remove this // `cfg` when `size_of_val_raw` is stabilized. #[cfg(__ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS)] -use core::ptr::{self, NonNull}; +use core::ptr; use crate::{ - pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants}, + pointer::{ + invariant::{self, BecauseExclusive, BecauseImmutable, Invariants}, + TryTransmuteFromPtr, + }, FromBytes, Immutable, IntoBytes, Ptr, TryFromBytes, ValidityError, }; @@ -548,7 +554,7 @@ pub unsafe fn transmute_mut<'dst, 'src: 'dst, Src: 'src, Dst: 'dst>( /// [`is_bit_valid`]: TryFromBytes::is_bit_valid #[doc(hidden)] #[inline] -fn try_cast_or_pme( +fn try_cast_or_pme( src: Ptr<'_, Src, I>, ) -> Result< Ptr<'_, Dst, (I::Aliasing, invariant::Unaligned, invariant::Valid)>, @@ -558,7 +564,9 @@ where // TODO(#2226): There should be a `Src: FromBytes` bound here, but doing so // requires deeper surgery. Src: invariant::Read, - Dst: TryFromBytes + invariant::Read, + Dst: TryFromBytes + + invariant::Read + + TryTransmuteFromPtr, I: Invariants, I::Aliasing: invariant::Reference, { @@ -570,7 +578,7 @@ where // `Src`. // - `p as *mut Dst` is a provenance-preserving cast #[allow(clippy::as_conversions)] - let c_ptr = unsafe { src.cast_unsized(|p| p as *mut Dst) }; + let c_ptr = unsafe { src.cast_unsized(NonNull::cast::) }; match c_ptr.try_into_valid() { Ok(ptr) => Ok(ptr), @@ -584,7 +592,7 @@ where // to the size of `Src`. // - `p as *mut Src` is a provenance-preserving cast #[allow(clippy::as_conversions)] - let ptr = unsafe { ptr.cast_unsized(|p| p as *mut Src) }; + let ptr = unsafe { ptr.cast_unsized(NonNull::cast::) }; // SAFETY: `ptr` is `src`, and has the same alignment invariant. let ptr = unsafe { ptr.assume_alignment::() }; // SAFETY: `ptr` is `src` and has the same validity invariant. @@ -637,8 +645,7 @@ where // // `MaybeUninit` is guaranteed to have the same size, alignment, and // ABI as `T` - let ptr: Ptr<'_, Dst, _> = - unsafe { ptr.cast_unsized(|mu: *mut mem::MaybeUninit| mu.cast()) }; + let ptr: Ptr<'_, Dst, _> = unsafe { ptr.cast_unsized(NonNull::>::cast) }; if Dst::is_bit_valid(ptr.forget_aligned()) { // SAFETY: Since `Dst::is_bit_valid`, we know that `ptr`'s referent is @@ -672,7 +679,7 @@ where { let ptr = Ptr::from_ref(src); let ptr = ptr.bikeshed_recall_initialized_immutable(); - match try_cast_or_pme::(ptr) { + match try_cast_or_pme::(ptr) { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter @@ -716,7 +723,7 @@ where { let ptr = Ptr::from_mut(src); let ptr = ptr.bikeshed_recall_initialized_from_bytes(); - match try_cast_or_pme::(ptr) { + match try_cast_or_pme::(ptr) { Ok(ptr) => { static_assert!(Src, Dst => mem::align_of::() <= mem::align_of::()); // SAFETY: We have checked that `Dst` does not have a stricter diff --git a/src/util/macros.rs b/src/util/macros.rs index c98711926e..78ff79a535 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -174,7 +174,7 @@ macro_rules! unsafe_impl { // - The caller has promised that the destination type has // `UnsafeCell`s at the same byte ranges as the source type. #[allow(clippy::as_conversions)] - let candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; + let candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| cast!(p => NonNull<_>)) }; // TODO(#1866): Currently, `bikeshed_recall_valid` has a known // soundness hole. Eventually this will need to be fixed by @@ -204,7 +204,7 @@ macro_rules! unsafe_impl { // - The caller has promised that the destination type has // `UnsafeCell`s at the same byte ranges as the source type. #[allow(clippy::as_conversions)] - let $candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; + let $candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| cast!(p => NonNull<_>)) }; $is_bit_valid } @@ -225,7 +225,86 @@ macro_rules! unsafe_impl { }; } -/// Implements `$trait` for a type which implements `TransparentWrapper`. +macro_rules! unsafe_impl_transmute_from_for_atomic { + ($($atomic:ty [$prim:ty]),*) => { + const _: () = { + use crate::pointer::{TransmuteFrom, invariant::Valid}; + + $( + unsafe impl TransmuteFrom<$atomic, Valid, Valid> for $prim {} + unsafe impl TransmuteFrom<$prim, Valid, Valid> for $atomic {} + + unsafe impl TransmuteFrom<$atomic, Valid, Valid> for core::cell::UnsafeCell<$prim> {} + unsafe impl TransmuteFrom, Valid, Valid> for $atomic {} + )* + }; + }; + ($($tyvar:ident => $atomic:ty [$prim:ty]),*) => { + const _: () = { + use crate::pointer::{TransmuteFrom, invariant::Valid}; + + $( + unsafe impl<$tyvar> TransmuteFrom<$atomic, Valid, Valid> for $prim {} + unsafe impl<$tyvar> TransmuteFrom<$prim, Valid, Valid> for $atomic {} + + unsafe impl<$tyvar> TransmuteFrom<$atomic, Valid, Valid> for core::cell::UnsafeCell<$prim> {} + unsafe impl<$tyvar> TransmuteFrom, Valid, Valid> for $atomic {} + )* + }; + } +} + +macro_rules! impl_for_transmute_from { + ( + $(#[$attr:meta])* + $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)? + => TryFromBytes for $ty:ty [UnsafeCell<$repr:ty>] + ) => { + unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> crate::TryFromBytes for $ty { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + + #[inline(always)] + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { + let c: Maybe<'_, Self, crate::pointer::invariant::Exclusive> = candidate.into_exclusive_or_pme(); + let c: Maybe<'_, $repr, _> = c.transmute::<_, _, (_, (_, (BecauseExclusive, BecauseExclusive)))>(); + <$repr as TryFromBytes>::is_bit_valid(c) + } + } + }; + ( + $(#[$attr:meta])* + $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)? + => TryFromBytes for $ty:ty [$repr:ty] + ) => { + unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> crate::TryFromBytes for $ty { + #[allow(clippy::missing_inline_in_public_items)] + fn only_derive_is_allowed_to_implement_this_trait() {} + + + impl_for_transmute_from!(@is_bit_valid $repr: $($($(? $optbound)*)?)?); + + // #[inline(always)] + // fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { + // let c: Maybe<'_, $repr, A> = candidate.transmute(); + // <$repr as TryFromBytes>::is_bit_valid(c) + // } + } + }; + (@is_bit_valid $repr:ty:) => { + #[inline(always)] + fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { + let c: Maybe<'_, $repr, A> = candidate.transmute_sized(); + <$repr as TryFromBytes>::is_bit_valid(c) + } + }; + (@is_bit_valid $repr:ty: ?Sized) => { + compile_error!("impl_for_transmute_from! does not currently support unsized types"); + } +} + +/// Implements `$trait` for `$ty` where `$ty: TransmuteFrom<$repr>` (and +/// vice-versa). /// /// Calling this macro is safe; the internals of the macro emit appropriate /// trait bounds which ensure that the given impl is sound. @@ -233,146 +312,68 @@ macro_rules! impl_for_transparent_wrapper { ( $(#[$attr:meta])* $($tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?)? - => $trait:ident for $ty:ty $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? + => $trait:ident for $ty:ty [$repr:ty] $(; |$candidate:ident $(: MaybeAligned<$ref_repr:ty>)? $(: Maybe<$ptr_repr:ty>)?| $is_bit_valid:expr)? ) => { $(#[$attr])* #[allow(non_local_definitions)] - // This block implements `$trait` for `$ty` under the following - // conditions: - // - `$ty: TransparentWrapper` - // - `$ty::Inner: $trait` - // - For some `Xxx`, `$ty::XxxVariance = Covariant` (`Xxx` is determined - // by the `@define_is_transparent_wrapper` macro arms). This bound - // ensures that some layout property is the same between `$ty` and - // `$ty::Inner`. Which layout property this is depends on the trait - // being implemented (for example, `FromBytes` is not concerned with - // alignment, but is concerned with bit validity). - // - // In other words, `$ty` is guaranteed to soundly implement `$trait` - // because some property of its layout is the same as `$ty::Inner`, - // which implements `$trait`. Most of the complexity in this macro is to - // ensure that the above-mentioned conditions are actually met, and that - // the proper variance (ie, the proper layout property) is chosen. - - // SAFETY: - // - `is_transparent_wrapper` requires: - // - `W: TransparentWrapper` - // - `W::Inner: $trait` - // - `f` is generic over `I: Invariants`, and in its body, calls - // `is_transparent_wrapper::()`. Thus, this code will only - // compile if, for all `I: Invariants`: - // - `$ty: TransparentWrapper` - // - `$ty::Inner: $trait` - // - // These two facts - that `$ty: TransparentWrapper` and that - // `$ty::Inner: $trait` - are the preconditions to the full safety - // proofs, which are completed below in the - // `@define_is_transparent_wrapper` macro arms. The safety proof is - // slightly different for each trait. + // SAFETY: `is_trait` (defined and used below) requires `T: + // TransmuteFrom`, `R: TransmuteFrom`, and `R: $trait`. It is + // called using `$ty` and `$repr`, ensuring that `$ty` and `$repr` have + // equivalent bit validity, and ensuring that `$repr: $trait`. The + // supported traits - `TryFromBytes`, `FromZeros`, `FromBytes`, and + // `IntoBytes` - are defined only in terms of the bit validity of a + // type. Therefore, `$repr: $trait` ensures that `$ty: $trait` is sound. unsafe impl<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?> $trait for $ty { #[allow(dead_code, clippy::missing_inline_in_public_items)] #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] fn only_derive_is_allowed_to_implement_this_trait() { - use crate::{pointer::invariant::Invariants, util::*}; + use crate::pointer::{*, invariant::Valid}; + + impl_for_transparent_wrapper!(@assert_is_supported_trait $trait); - impl_for_transparent_wrapper!(@define_is_transparent_wrapper $trait); + fn is_trait() + where + T: TransmuteFrom + ?Sized, + R: TransmuteFrom + ?Sized, + R: $trait, + { + } #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] - fn f() { - is_transparent_wrapper::(); + fn f<$($tyvar $(: $(? $optbound +)* $($bound +)*)?)?>() { + is_trait::<$ty, $repr>(); } } impl_for_transparent_wrapper!( @is_bit_valid $(<$tyvar $(: $(? $optbound +)* $($bound +)*)?>)? - $trait for $ty + $trait for $ty[$repr] ); } }; - (@define_is_transparent_wrapper Immutable) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has `UnsafeCell`s at the same byte offsets as - // `W::Inner`. `W::Inner: Immutable` implies that `W::Inner` does not - // contain any `UnsafeCell`s, and so `W` does not contain any - // `UnsafeCell`s. Since `W = $ty`, `$ty` can soundly implement - // `Immutable`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper Immutable, UnsafeCellVariance) - }; - (@define_is_transparent_wrapper FromZeros) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // FromZeros` implies that the all-zeros bit pattern is a bit-valid - // instance of `W::Inner`, and so the all-zeros bit pattern is a - // bit-valid instance of `W`. Since `W = $ty`, `$ty` can soundly - // implement `FromZeros`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper FromZeros, ValidityVariance) - }; - (@define_is_transparent_wrapper FromBytes) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // FromBytes` implies that any initialized bit pattern is a bit-valid - // instance of `W::Inner`, and so any initialized bit pattern is a - // bit-valid instance of `W`. Since `W = $ty`, `$ty` can soundly - // implement `FromBytes`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper FromBytes, ValidityVariance) - }; - (@define_is_transparent_wrapper IntoBytes) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // IntoBytes` implies that no bit-valid instance of `W::Inner` contains - // uninitialized bytes, and so no bit-valid instance of `W` contains - // uninitialized bytes. Since `W = $ty`, `$ty` can soundly implement - // `IntoBytes`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper IntoBytes, ValidityVariance) - }; - (@define_is_transparent_wrapper Unaligned) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same alignment as `W::Inner`. `W::Inner: - // Unaligned` implies `W::Inner`'s alignment is 1, and so `W`'s - // alignment is 1. Since `W = $ty`, `W` can soundly implement - // `Unaligned`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper Unaligned, AlignmentVariance) - }; - (@define_is_transparent_wrapper TryFromBytes) => { - // SAFETY: `W: TransparentWrapper` - // requires that `W` has the same bit validity as `W::Inner`. `W::Inner: - // TryFromBytes` implies that `::is_bit_valid(c)` only returns `true` if `c` references - // a bit-valid instance of `W::Inner`. Thus, `::is_bit_valid(c)` only returns `true` if `c` references - // a bit-valid instance of `W`. Below, we implement `::is_bit_valid` by deferring to `::is_bit_valid`. Since `W = $ty`, it is sound for `$ty` - // to implement `TryFromBytes` with this implementation of - // `is_bit_valid`. - impl_for_transparent_wrapper!(@define_is_transparent_wrapper TryFromBytes, ValidityVariance) - }; - (@define_is_transparent_wrapper $trait:ident, $variance:ident) => { - #[cfg_attr(all(coverage_nightly, __ZEROCOPY_INTERNAL_USE_ONLY_NIGHTLY_FEATURES_IN_TESTS), coverage(off))] - fn is_transparent_wrapper + ?Sized>() - where - W::Inner: $trait, - {} - }; + (@assert_is_supported_trait TryFromBytes) => {}; + (@assert_is_supported_trait FromZeros) => {}; + (@assert_is_supported_trait FromBytes) => {}; + (@assert_is_supported_trait IntoBytes) => {}; ( @is_bit_valid $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? - TryFromBytes for $ty:ty + TryFromBytes for $ty:ty[$repr:ty] ) => { // SAFETY: See safety comment in `(@define_is_transparent_wrapper // TryFromBytes)` macro arm for an explanation of why this is a sound // implementation of `is_bit_valid`. #[inline] fn is_bit_valid(candidate: Maybe<'_, Self, A>) -> bool { - TryFromBytes::is_bit_valid(candidate.transparent_wrapper_into_inner()) + <$repr as TryFromBytes>::is_bit_valid(candidate.transmute()) } }; ( @is_bit_valid $(<$tyvar:ident $(: $(? $optbound:ident $(+)?)* $($bound:ident $(+)?)* )?>)? - $trait:ident for $ty:ty + $trait:ident for $ty:ty[$repr:ty] ) => { // Trait other than `TryFromBytes`; no `is_bit_valid` impl. }; @@ -803,3 +804,26 @@ macro_rules! static_assert_dst_is_not_zst { }, "cannot call this method on a dynamically-sized type whose trailing slice element is zero-sized"); }} } + +macro_rules! cast { + ($e:expr => NonNull<$t:ty>) => { + // SAFETY: `NonNull::as_ptr` returns a non-null pointer, so the argument + // to `NonNull::new_unchecked` is also non-null. + unsafe { core::ptr::NonNull::new_unchecked(core::ptr::NonNull::as_ptr($e) as *mut $t) } + }; +} + +#[rustfmt::skip] +macro_rules! impl_size_eq { + ($t:ty, $u:ty) => { + const _: () = { + use {crate::pointer::SizeEq, core::mem::size_of}; + static_assert!(=> size_of::<$t>() == size_of::<$u>()); + + // SAFETY: The preceding assert ensures that sizes are equal. + unsafe impl SizeEq<$t> for $u {} + // SAFETY: The preceding assert ensures that sizes are equal. + unsafe impl SizeEq<$u> for $t {} + }; + }; +} diff --git a/src/util/mod.rs b/src/util/mod.rs index e3302aa1e8..506254a1c7 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -13,465 +13,15 @@ mod macros; pub mod macro_util; use core::{ - cell::UnsafeCell, marker::PhantomData, mem::{self, ManuallyDrop, MaybeUninit}, - num::{NonZeroUsize, Wrapping}, + num::NonZeroUsize, ptr::NonNull, }; -use crate::{ - error::AlignmentError, - pointer::invariant::{self, Invariants}, - Unalign, -}; - -/// A type which has the same layout as the type it wraps. -/// -/// # Safety -/// -/// `T: TransparentWrapper` implies that `T` has the same size as [`T::Inner`]. -/// Further, `T: TransparentWrapper` implies that: -/// - If `T::UnsafeCellVariance = Covariant`, then `T` has `UnsafeCell`s -/// covering the same byte ranges as `T::Inner`. -/// - If a `T` pointer satisfies the alignment invariant `I::Alignment`, then -/// that same pointer, cast to `T::Inner`, satisfies the alignment invariant -/// `>::Applied`. -/// - If a `T` pointer satisfies the validity invariant `I::Validity`, then that -/// same pointer, cast to `T::Inner`, satisfies the validity invariant -/// `>::Applied`. -/// -/// [`T::Inner`]: TransparentWrapper::Inner -/// [`UnsafeCell`]: core::cell::UnsafeCell -/// [`T::AlignmentVariance`]: TransparentWrapper::AlignmentVariance -/// [`T::ValidityVariance`]: TransparentWrapper::ValidityVariance -#[doc(hidden)] -pub unsafe trait TransparentWrapper { - type Inner: ?Sized; - - type UnsafeCellVariance; - type AlignmentVariance: AlignmentVariance; - type ValidityVariance: ValidityVariance; - - /// Casts a wrapper pointer to an inner pointer. - /// - /// # Safety - /// - /// The resulting pointer has the same address and provenance as `ptr`, and - /// addresses the same number of bytes. - fn cast_into_inner(ptr: *mut Self) -> *mut Self::Inner; - - /// Casts an inner pointer to a wrapper pointer. - /// - /// # Safety - /// - /// The resulting pointer has the same address and provenance as `ptr`, and - /// addresses the same number of bytes. - fn cast_from_inner(ptr: *mut Self::Inner) -> *mut Self; -} - -#[allow(unreachable_pub)] -#[doc(hidden)] -pub trait AlignmentVariance { - type Applied: invariant::Alignment; -} - -#[allow(unreachable_pub)] -#[doc(hidden)] -pub trait ValidityVariance { - type Applied: invariant::Validity; -} - -#[doc(hidden)] -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum Covariant {} - -impl AlignmentVariance for Covariant { - type Applied = I; -} - -impl ValidityVariance for Covariant { - type Applied = I; -} - -#[doc(hidden)] -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum Invariant {} - -impl AlignmentVariance for Invariant { - type Applied = invariant::Unaligned; -} - -impl ValidityVariance for Invariant { - type Applied = invariant::Uninit; -} - -// SAFETY: -// - Per [1], `MaybeUninit` has the same size as `T`. -// - See inline comments for other safety justifications. -// -// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1: -// -// `MaybeUninit` is guaranteed to have the same size, alignment, and ABI as -// `T` -unsafe impl TransparentWrapper for MaybeUninit { - type Inner = T; - - // SAFETY: `MaybeUninit` has `UnsafeCell`s covering the same byte ranges - // as `Inner = T`. This is not explicitly documented, but it can be - // inferred. Per [1] in the preceding safety comment, `MaybeUninit` has - // the same size as `T`. Further, note the signature of - // `MaybeUninit::assume_init_ref` [2]: - // - // pub unsafe fn assume_init_ref(&self) -> &T - // - // If the argument `&MaybeUninit` and the returned `&T` had `UnsafeCell`s - // at different offsets, this would be unsound. Its existence is proof that - // this is not the case. - // - // [2] https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#method.assume_init_ref - type UnsafeCellVariance = Covariant; - // SAFETY: Per [1], `MaybeUninit` has the same layout as `T`, and thus - // has the same alignment as `T`. - // - // [1] Per https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#layout-1: - // - // `MaybeUninit` is guaranteed to have the same size, alignment, and - // ABI as `T`. - type AlignmentVariance = Covariant; - // SAFETY: `MaybeUninit` has no validity invariants. Thus, a valid - // `MaybeUninit` is not necessarily a valid `T`. - type ValidityVariance = Invariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut MaybeUninit) -> *mut T { - // SAFETY: Per [1] (from comment above), `MaybeUninit` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::() - } - - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut MaybeUninit { - // SAFETY: Per [1] (from comment above), `MaybeUninit` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() - } -} - -// SAFETY: -// - Per [1], `ManuallyDrop` has the same size as `T`. -// - See inline comments for other safety justifications. -// -// [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: -// -// `ManuallyDrop` is guaranteed to have the same layout and bit validity as -// `T` -unsafe impl TransparentWrapper for ManuallyDrop { - type Inner = T; - - // SAFETY: Per [1], `ManuallyDrop` has `UnsafeCell`s covering the same - // byte ranges as `Inner = T`. - // - // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/struct.ManuallyDrop.html: - // - // `ManuallyDrop` is guaranteed to have the same layout and bit - // validity as `T`, and is subject to the same layout optimizations as - // `T`. As a consequence, it has no effect on the assumptions that the - // compiler makes about its contents. - type UnsafeCellVariance = Covariant; - // SAFETY: Per [1], `ManuallyDrop` has the same layout as `T`, and thus - // has the same alignment as `T`. - // - // [1] Per https://doc.rust-lang.org/nightly/core/mem/struct.ManuallyDrop.html: - // - // `ManuallyDrop` is guaranteed to have the same layout and bit - // validity as `T` - type AlignmentVariance = Covariant; - - // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same bit - // validity as `T`. - type ValidityVariance = Covariant; +use zerocopy_derive::TryFromBytes; - #[inline(always)] - fn cast_into_inner(ptr: *mut ManuallyDrop) -> *mut T { - // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same - // layout as `T`. Thus, this cast preserves size even if `T` is unsized. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut T; - } - - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut ManuallyDrop { - // SAFETY: Per [1] (from comment above), `ManuallyDrop` has the same - // layout as `T`. Thus, this cast preserves size even if `T` is unsized. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut ManuallyDrop; - } -} - -// SAFETY: -// - Per [1], `Wrapping` has the same size as `T`. -// - See inline comments for other safety justifications. -// -// [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: -// -// `Wrapping` is guaranteed to have the same layout and ABI as `T`. -unsafe impl TransparentWrapper for Wrapping { - type Inner = T; - - // SAFETY: Per [1], `Wrapping` has the same layout as `T`. Since its - // single field (of type `T`) is public, it would be a breaking change to - // add or remove fields. Thus, we know that `Wrapping` contains a `T` (as - // opposed to just having the same size and alignment as `T`) with no pre- - // or post-padding. Thus, `Wrapping` must have `UnsafeCell`s covering the - // same byte ranges as `Inner = T`. - // - // [1] Per https://doc.rust-lang.org/1.81.0/std/num/struct.Wrapping.html#layout-1: - // - // `Wrapping` is guaranteed to have the same layout and ABI as `T`. - type UnsafeCellVariance = Covariant; - // SAFETY: Per [1], `Wrapping` has the same layout as `T`, and thus has - // the same alignment as `T`. - // - // [1] Per https://doc.rust-lang.org/core/num/struct.Wrapping.html#layout-1: - // - // `Wrapping` is guaranteed to have the same layout and ABI as `T`. - type AlignmentVariance = Covariant; - - // SAFETY: `Wrapping` has only one field, which is `pub` [2]. We are also - // guaranteed per [1] (from the comment above) that `Wrapping` has the - // same layout as `T`. The only way for both of these to be true - // simultaneously is for `Wrapping` to have the same bit validity as `T`. - // In particular, in order to change the bit validity, one of the following - // would need to happen: - // - `Wrapping` could change its `repr`, but this would violate the layout - // guarantee. - // - `Wrapping` could add or change its fields, but this would be a - // stability-breaking change. - // - // [2] https://doc.rust-lang.org/core/num/struct.Wrapping.html - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut Wrapping) -> *mut T { - // SAFETY: Per [1] (from comment above), `Wrapping` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::() - } - - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut Wrapping { - // SAFETY: Per [1] (from comment above), `Wrapping` has the same - // layout as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() - } -} - -// SAFETY: -// - Per [1], `UnsafeCell` has the same size as `T`. -// - See inline comments for other safety justifications. -// -// [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: -// -// `UnsafeCell` has the same in-memory representation as its inner type -// `T`. -unsafe impl TransparentWrapper for UnsafeCell { - type Inner = T; - - // SAFETY: Since we set this to `Invariant`, we make no safety claims. - type UnsafeCellVariance = Invariant; - - // SAFETY: Per [1] (from comment on impl), `Unalign` has the same - // representation as `T`, and thus has the same alignment as `T`. - type AlignmentVariance = Covariant; - - // SAFETY: Per [1], `Unalign` has the same bit validity as `T`. - // Technically the term "representation" doesn't guarantee this, but the - // subsequent sentence in the documentation makes it clear that this is the - // intention. - // - // [1] Per https://doc.rust-lang.org/1.81.0/core/cell/struct.UnsafeCell.html#memory-layout: - // - // `UnsafeCell` has the same in-memory representation as its inner type - // `T`. A consequence of this guarantee is that it is possible to convert - // between `T` and `UnsafeCell`. - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut UnsafeCell) -> *mut T { - // SAFETY: Per [1] (from comment above), `UnsafeCell` has the same - // representation as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut T; - } - - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut UnsafeCell { - // SAFETY: Per [1] (from comment above), `UnsafeCell` has the same - // representation as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - #[allow(clippy::as_conversions)] - return ptr as *mut UnsafeCell; - } -} - -// SAFETY: `Unalign` promises to have the same size as `T`. -// -// See inline comments for other safety justifications. -unsafe impl TransparentWrapper for Unalign { - type Inner = T; - - // SAFETY: `Unalign` promises to have `UnsafeCell`s covering the same - // byte ranges as `Inner = T`. - type UnsafeCellVariance = Covariant; - - // SAFETY: Since `Unalign` promises to have alignment 1 regardless of - // `T`'s alignment. Thus, an aligned pointer to `Unalign` is not - // necessarily an aligned pointer to `T`. - type AlignmentVariance = Invariant; - - // SAFETY: `Unalign` promises to have the same validity as `T`. - type ValidityVariance = Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut Unalign) -> *mut T { - // SAFETY: Per the safety comment on the impl block, `Unalign` has - // the size as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::() - } - - #[inline(always)] - fn cast_from_inner(ptr: *mut T) -> *mut Unalign { - // SAFETY: Per the safety comment on the impl block, `Unalign` has - // the size as `T`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() - } -} - -/// Implements `TransparentWrapper` for an atomic type. -/// -/// # Safety -/// -/// The caller promises that `$atomic` is an atomic type whose natie equivalent -/// is `$native`. -#[cfg(all( - zerocopy_target_has_atomics_1_60_0, - any( - target_has_atomic = "8", - target_has_atomic = "16", - target_has_atomic = "32", - target_has_atomic = "64", - target_has_atomic = "ptr" - ) -))] -macro_rules! unsafe_impl_transparent_wrapper_for_atomic { - ($(#[$attr:meta])* $(,)?) => {}; - ($(#[$attr:meta])* $atomic:ty [$native:ty], $($atomics:ty [$natives:ty]),* $(,)?) => { - $(#[$attr])* - // SAFETY: See safety comment in next match arm. - unsafe impl crate::util::TransparentWrapper for $atomic { - unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); - } - unsafe_impl_transparent_wrapper_for_atomic!($(#[$attr])* $($atomics [$natives],)*); - }; - ($(#[$attr:meta])* $tyvar:ident => $atomic:ty [$native:ty]) => { - // We implement for `$atomic` and set `Inner = $native`. The caller has - // promised that `$atomic` and `$native` are an atomic type and its - // native counterpart, respectively. Per [1], `$atomic` and `$native` - // have the same size. - // - // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: - // - // This type has the same size and bit validity as the underlying - // integer type - $(#[$attr])* - unsafe impl<$tyvar, I: crate::invariant::Invariants> crate::util::TransparentWrapper for $atomic { - unsafe_impl_transparent_wrapper_for_atomic!(@inner $atomic [$native]); - } - }; - (@inner $atomic:ty [$native:ty]) => { - type Inner = UnsafeCell<$native>; - - // SAFETY: It is "obvious" that each atomic type contains a single - // `UnsafeCell` that covers all bytes of the type, but we can also prove - // it: - // - Since `$atomic` provides an API which permits loading and storing - // values of type `$native` via a `&self` (shared) reference, *some* - // interior mutation must be happening, and interior mutation can only - // happen via `UnsafeCell`. Further, there must be enough bytes in - // `$atomic` covered by an `UnsafeCell` to hold every possible value - // of `$native`. - // - Per [1], `$atomic` has the same size as `$native`. This on its own - // isn't enough: it would still be possible for `$atomic` to store - // `$native` using a compact representation (for `$native` types for - // which some bit patterns are illegal). However, this is ruled out by - // the fact that `$atomic` has the same bit validity as `$native` [1]. - // Thus, we can conclude that every byte of `$atomic` must be covered - // by an `UnsafeCell`. - // - // Thus, every byte of `$atomic` is covered by an `UnsafeCell`, and we - // set `type Inner = UnsafeCell<$native>`. Thus, `Self` and - // `Self::Inner` have `UnsafeCell`s covering the same byte ranges. - // - // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: - // - // This type has the same size and bit validity as the underlying - // integer type - type UnsafeCellVariance = crate::util::Covariant; - - // SAFETY: No safety justification is required for an invariant - // variance. - type AlignmentVariance = crate::util::Invariant; - - // SAFETY: Per [1], all atomic types have the same bit validity as their - // native counterparts. The caller has promised that `$atomic` and - // `$native` are an atomic type and its native counterpart, - // respectively. - // - // [1] Per (for example) https://doc.rust-lang.org/1.81.0/std/sync/atomic/struct.AtomicU64.html: - // - // This type has the same size and bit validity as the underlying - // integer type - type ValidityVariance = crate::util::Covariant; - - #[inline(always)] - fn cast_into_inner(ptr: *mut $atomic) -> *mut UnsafeCell<$native> { - // SAFETY: Per [1] (from comment on impl block), `$atomic` has the - // same size as `$native`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::>() - } - - #[inline(always)] - fn cast_from_inner(ptr: *mut UnsafeCell<$native>) -> *mut $atomic { - // SAFETY: Per [1] (from comment on impl block), `$atomic` has the - // same size as `$native`. Thus, this cast preserves size. - // - // This cast trivially preserves provenance. - ptr.cast::<$atomic>() - } - }; -} +use crate::{error::AlignmentError, KnownLayout}; /// Like [`PhantomData`], but [`Send`] and [`Sync`] regardless of whether the /// wrapped `T` is. @@ -904,6 +454,16 @@ pub(crate) mod polyfills { } } +#[derive(KnownLayout, TryFromBytes)] +#[repr(transparent)] +pub(crate) struct SizedKnownLayout(T); + +unsafe impl crate::pointer::SizeEq for SizedKnownLayout {} +unsafe impl crate::pointer::SizeEq> for T {} + +unsafe impl crate::pointer::SizeEq> for SizedKnownLayout {} +unsafe impl crate::pointer::SizeEq> for MaybeUninit {} + #[cfg(test)] pub(crate) mod testutil { use crate::*; diff --git a/src/wrappers.rs b/src/wrappers.rs index fd48236ae4..408db3ed78 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -188,7 +188,7 @@ impl Unalign { /// may prefer [`Deref::deref`], which is infallible. #[inline(always)] pub fn try_deref(&self) -> Result<&T, AlignmentError<&Self, T>> { - let inner = Ptr::from_ref(self).transparent_wrapper_into_inner(); + let inner = Ptr::from_ref(self).transmute_sized(); match inner.bikeshed_try_into_aligned() { Ok(aligned) => Ok(aligned.as_ref()), Err(err) => Err(err.map_src(|src| src.into_unalign().as_ref())), @@ -205,7 +205,7 @@ impl Unalign { /// callers may prefer [`DerefMut::deref_mut`], which is infallible. #[inline(always)] pub fn try_deref_mut(&mut self) -> Result<&mut T, AlignmentError<&mut Self, T>> { - let inner = Ptr::from_mut(self).transparent_wrapper_into_inner(); + let inner = Ptr::from_mut(self).transmute_sized::<_, _, (_, (_, _))>(); match inner.bikeshed_try_into_aligned() { Ok(aligned) => Ok(aligned.as_mut()), Err(err) => Err(err.map_src(|src| src.into_unalign().as_mut())), @@ -394,14 +394,17 @@ impl Deref for Unalign { #[inline(always)] fn deref(&self) -> &T { - Ptr::from_ref(self).transparent_wrapper_into_inner().bikeshed_recall_aligned().as_ref() + Ptr::from_ref(self).transmute_sized().bikeshed_recall_aligned().as_ref() } } impl DerefMut for Unalign { #[inline(always)] fn deref_mut(&mut self) -> &mut T { - Ptr::from_mut(self).transparent_wrapper_into_inner().bikeshed_recall_aligned().as_mut() + Ptr::from_mut(self) + .transmute_sized::<_, _, (_, (_, _))>() + .bikeshed_recall_aligned() + .as_mut() } } diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 6da4fcffce..74f78362fd 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -653,6 +653,8 @@ fn derive_try_from_bytes_struct( where ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { + use ::zerocopy::util::macro_util::core_reexport; + true #(&& { // SAFETY: // - `project` is a field projection, and so it addresses a @@ -662,8 +664,14 @@ fn derive_try_from_bytes_struct( // the same byte ranges in the returned pointer's referent // as they do in `*slf` let field_candidate = unsafe { - let project = |slf: *mut Self| - ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).#field_names); + let project = |slf: core_reexport::ptr::NonNull| { + let slf = slf.as_ptr(); + let field = core_reexport::ptr::addr_of_mut!((*slf).#field_names); + // TODO: Safety comment. Needs precondition that the + // original `slf` pointer doesn't wrap around + // address space. + unsafe { core_reexport::ptr::NonNull::new_unchecked(field) } + }; candidate.reborrow().cast_unsized_unchecked(project) }; @@ -711,6 +719,8 @@ fn derive_try_from_bytes_union( where ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, { + use ::zerocopy::util::macro_util::core_reexport; + false #(|| { // SAFETY: // - `project` is a field projection, and so it addresses a @@ -720,8 +730,14 @@ fn derive_try_from_bytes_union( // `self_type_trait_bounds`, neither `*slf` nor the // returned pointer's referent contain any `UnsafeCell`s let field_candidate = unsafe { - let project = |slf: *mut Self| - ::zerocopy::util::macro_util::core_reexport::ptr::addr_of_mut!((*slf).#field_names); + let project = |slf: core_reexport::ptr::NonNull| { + let slf = slf.as_ptr(); + let field = core_reexport::ptr::addr_of_mut!((*slf).#field_names); + // TODO: Safety comment. Needs precondition that the + // original `slf` pointer doesn't wrap around + // address space. + unsafe { core_reexport::ptr::NonNull::new_unchecked(field) } + }; candidate.reborrow().cast_unsized_unchecked(project) };