diff --git a/src/impls.rs b/src/impls.rs index a040a79df7..97c00ee62f 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -105,11 +105,13 @@ assert_unaligned!(bool); // pattern 0x01. const _: () = unsafe { unsafe_impl!(=> TryFromBytes for bool; |byte| { - let byte = byte.transmute::(); + let mut byte = byte; + let byte = byte.reborrow().into_shared().transmute::(); *byte.unaligned_as_ref() < 2 }) }; -impl_size_eq!(bool, u8); + +impl_size_from!(bool, u8); // SAFETY: // - `Immutable`: `char` self-evidently does not contain any `UnsafeCell`s. @@ -134,13 +136,14 @@ const _: () = unsafe { unsafe_impl!(char: Immutable, FromZeros, IntoBytes) }; // `char`. const _: () = unsafe { unsafe_impl!(=> TryFromBytes for char; |c| { - let c = c.transmute::, invariant::Valid, _>(); + let mut c = c; + let c = c.reborrow().into_shared().transmute::, invariant::Valid, _>(); let c = c.read_unaligned().into_inner(); char::from_u32(c).is_some() }); }; -impl_size_eq!(char, Unalign); +impl_size_from!(char, Unalign); // SAFETY: Per the Reference [1], `str` has the same layout as `[u8]`. // - `Immutable`: `[u8]` does not contain any `UnsafeCell`s. @@ -167,21 +170,22 @@ const _: () = unsafe { unsafe_impl!(str: Immutable, FromZeros, IntoBytes, Unalig // Returns `Err` if the slice is not UTF-8. const _: () = unsafe { unsafe_impl!(=> TryFromBytes for str; |c| { - let c = c.transmute::<[u8], invariant::Valid, _>(); + let mut c = c; + let c = c.reborrow().into_shared().transmute::<[u8], invariant::Valid, _>(); let c = c.unaligned_as_ref(); core::str::from_utf8(c).is_ok() }) }; -impl_size_eq!(str, [u8]); +impl_size_from!(str, [u8]); macro_rules! unsafe_impl_try_from_bytes_for_nonzero { ($($nonzero:ident[$prim:ty]),*) => { $( unsafe_impl!(=> TryFromBytes for $nonzero; |n| { - impl_size_eq!($nonzero, Unalign<$prim>); - - let n = n.transmute::, invariant::Valid, _>(); + impl_size_from!($nonzero, Unalign<$prim>); + let mut n = n; + let n = n.reborrow().into_shared().transmute::, invariant::Valid, _>(); $nonzero::new(n.read_unaligned().into_inner()).is_some() }); )* @@ -396,45 +400,51 @@ mod atomics { ($($($tyvar:ident)? => $atomic:ty [$prim:ty]),*) => {{ crate::util::macros::__unsafe(); - use core::cell::UnsafeCell; - use crate::pointer::{PtrInner, SizeEq, TransmuteFrom, invariant::Valid}; + use core::{cell::UnsafeCell}; + use crate::pointer::{TransmuteFrom, PtrInner, SizeFrom, invariant::Valid}; $( // SAFETY: The caller promised that `$atomic` and `$prim` have - // the same size and bit validity. + // the same size and bit validity. As a result of size equality, + // both impls of `SizeFrom::cast_from_raw` preserve referent + // size exactly. unsafe impl<$($tyvar)?> TransmuteFrom<$atomic, Valid, Valid> for $prim {} // SAFETY: The caller promised that `$atomic` and `$prim` have - // the same size and bit validity. + // the same size and bit validity. As a result of size equality, + // both impls of `SizeFrom::cast_from_raw` preserve referent + // size exactly. unsafe impl<$($tyvar)?> TransmuteFrom<$prim, Valid, Valid> for $atomic {} - // SAFETY: The caller promised that `$atomic` and `$prim` have - // the same size. - unsafe impl<$($tyvar)?> SizeEq<$atomic> for $prim { + // SAFETY: See inline safety comment. + unsafe impl<$($tyvar)?> SizeFrom<$atomic> for $prim { #[inline] fn cast_from_raw(a: PtrInner<'_, $atomic>) -> PtrInner<'_, $prim> { - // SAFETY: The caller promised that `$atomic` and - // `$prim` have the same size. Thus, this cast preserves + // SAFETY: The caller promised that `$atomic` and `$prim` + // have the same size. Thus, this cast preserves // address, referent size, and provenance. unsafe { cast!(a) } } } // SAFETY: See previous safety comment. - unsafe impl<$($tyvar)?> SizeEq<$prim> for $atomic { + unsafe impl<$($tyvar)?> SizeFrom<$prim> for $atomic { #[inline] fn cast_from_raw(p: PtrInner<'_, $prim>) -> PtrInner<'_, $atomic> { // SAFETY: See previous safety comment. unsafe { cast!(p) } } } - // SAFETY: The caller promised that `$atomic` and `$prim` have - // the same size. `UnsafeCell` has the same size as `T` [1]. + + // SAFETY: The caller promised that `$atomic` and `$prim` + // have the same size. `UnsafeCell` has the same size as + // `T` [1]. Thus, this cast preserves address, referent + // size, and provenance. // // [1] Per https://doc.rust-lang.org/1.85.0/std/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<$($tyvar)?> SizeEq<$atomic> for UnsafeCell<$prim> { + unsafe impl<$($tyvar)?> SizeFrom<$atomic> for UnsafeCell<$prim> { #[inline] fn cast_from_raw(a: PtrInner<'_, $atomic>) -> PtrInner<'_, UnsafeCell<$prim>> { // SAFETY: See previous safety comment. @@ -442,7 +452,7 @@ mod atomics { } } // SAFETY: See previous safety comment. - unsafe impl<$($tyvar)?> SizeEq> for $atomic { + unsafe impl<$($tyvar)?> SizeFrom> for $atomic { #[inline] fn cast_from_raw(p: PtrInner<'_, UnsafeCell<$prim>>) -> PtrInner<'_, $atomic> { // SAFETY: See previous safety comment. @@ -452,7 +462,9 @@ mod atomics { // SAFETY: The caller promised that `$atomic` and `$prim` have // the same bit validity. `UnsafeCell` has the same bit - // validity as `T` [1]. + // validity as `T` [1]. `UnsafeCell` also has the same size + // as `T` [1], and so both impls of `SizeFrom::cast_from_raw` + // preserve referent size exactly. // // [1] Per https://doc.rust-lang.org/1.85.0/std/cell/struct.UnsafeCell.html#memory-layout: // diff --git a/src/layout.rs b/src/layout.rs index 54cb21ad58..b45fb26518 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -612,15 +612,15 @@ pub(crate) use cast_from_raw::cast_from_raw; mod cast_from_raw { use crate::{pointer::PtrInner, *}; - /// Implements [`>::cast_from_raw`][cast_from_raw]. + /// Implements [`>::cast_from_raw`][cast_from_raw]. /// /// # PME /// /// Generates a post-monomorphization error if it is not possible to satisfy - /// the soundness conditions of [`SizeEq::cast_from_raw`][cast_from_raw] + /// the soundness conditions of [`SizeCompat::cast_from_raw`][cast_from_raw] /// for `Src` and `Dst`. /// - /// [cast_from_raw]: crate::pointer::SizeEq::cast_from_raw + /// [cast_from_raw]: crate::pointer::SizeCompat::cast_from_raw // // FIXME(#1817): Support Sized->Unsized and Unsized->Sized casts pub(crate) fn cast_from_raw(src: PtrInner<'_, Src>) -> PtrInner<'_, Dst> diff --git a/src/lib.rs b/src/lib.rs index e305be9c1c..84f6b0118f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -381,7 +381,7 @@ use core::{ #[cfg(feature = "std")] use std::io; -use crate::pointer::invariant::{self, BecauseExclusive}; +use crate::pointer::{invariant, BecauseBidirectional}; #[cfg(any(feature = "alloc", test, kani))] extern crate alloc; @@ -1840,7 +1840,7 @@ pub unsafe trait TryFromBytes { Self: KnownLayout + IntoBytes, { static_assert_dst_is_not_zst!(Self); - match Ptr::from_mut(bytes).try_cast_into_no_leftover::(None) { + match Ptr::from_mut(bytes).try_cast_into_no_leftover(None) { Ok(source) => { // 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 @@ -1852,9 +1852,7 @@ pub unsafe trait TryFromBytes { // condition will not happen. match source.try_into_valid() { Ok(source) => Ok(source.as_mut()), - Err(e) => { - Err(e.map_src(|src| src.as_bytes::().as_mut()).into()) - } + Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()), } } Err(e) => Err(e.map_src(Ptr::as_mut).into()), @@ -2421,8 +2419,7 @@ pub unsafe trait TryFromBytes { where Self: KnownLayout + IntoBytes, { - match Ptr::from_mut(source).try_cast_into_no_leftover::(Some(count)) - { + match Ptr::from_mut(source).try_cast_into_no_leftover(Some(count)) { Ok(source) => { // 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 @@ -2434,9 +2431,7 @@ pub unsafe trait TryFromBytes { // condition will not happen. match source.try_into_valid() { Ok(source) => Ok(source.as_mut()), - Err(e) => { - Err(e.map_src(|src| src.as_bytes::().as_mut()).into()) - } + Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()), } } Err(e) => Err(e.map_src(Ptr::as_mut).into()), @@ -2844,7 +2839,7 @@ fn try_mut_from_prefix_suffix, ) -> Result<(&mut T, &mut [u8]), TryCastError<&mut [u8], T>> { - match Ptr::from_mut(candidate).try_cast_into::(cast_type, meta) { + match Ptr::from_mut(candidate).try_cast_into(cast_type, meta) { Ok((candidate, prefix_suffix)) => { // 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 @@ -2856,7 +2851,7 @@ fn try_mut_from_prefix_suffix Ok((valid.as_mut(), prefix_suffix.as_mut())), - Err(e) => Err(e.map_src(|src| src.as_bytes::().as_mut()).into()), + Err(e) => Err(e.map_src(|src| src.as_bytes().as_mut()).into()), } } Err(e) => Err(e.map_src(Ptr::as_mut).into()), @@ -3835,8 +3830,8 @@ pub unsafe trait FromBytes: FromZeros { Self: IntoBytes + KnownLayout, { static_assert_dst_is_not_zst!(Self); - match Ptr::from_mut(source).try_cast_into_no_leftover::<_, BecauseExclusive>(None) { - Ok(ptr) => Ok(ptr.recall_validity::<_, (_, (_, _))>().as_mut()), + match Ptr::from_mut(source).try_cast_into_no_leftover(None) { + Ok(ptr) => Ok(ptr.recall_validity::<_, BecauseBidirectional>().as_mut()), Err(err) => Err(err.map_src(|src| src.as_mut())), } } @@ -4304,11 +4299,9 @@ pub unsafe trait FromBytes: FromZeros { Self: IntoBytes + KnownLayout + Immutable, { let source = Ptr::from_mut(source); - let maybe_slf = source.try_cast_into_no_leftover::<_, BecauseImmutable>(Some(count)); + let maybe_slf = source.try_cast_into_no_leftover(Some(count)); match maybe_slf { - Ok(slf) => Ok(slf - .recall_validity::<_, (_, (_, (BecauseExclusive, BecauseExclusive)))>() - .as_mut()), + Ok(slf) => Ok(slf.recall_validity::<_, BecauseBidirectional>().as_mut()), Err(err) => Err(err.map_src(|s| s.as_mut())), } } @@ -4665,7 +4658,7 @@ pub unsafe trait FromBytes: FromZeros { // cannot be violated even though `buf` may have more permissive bit // validity than `ptr`. let ptr = unsafe { ptr.assume_validity::() }; - let ptr = ptr.as_bytes::(); + let ptr = ptr.as_bytes(); src.read_exact(ptr.as_mut())?; // SAFETY: `buf` entirely consists of initialized bytes, and `Self` is // `FromBytes`. @@ -4784,9 +4777,9 @@ fn mut_from_prefix_suffix( cast_type: CastType, ) -> Result<(&mut T, &mut [u8]), CastError<&mut [u8], T>> { let (slf, prefix_suffix) = Ptr::from_mut(source) - .try_cast_into::<_, BecauseExclusive>(cast_type, meta) + .try_cast_into(cast_type, meta) .map_err(|err| err.map_src(|s| s.as_mut()))?; - Ok((slf.recall_validity::<_, (_, (_, _))>().as_mut(), prefix_suffix.as_mut())) + Ok((slf.recall_validity::<_, BecauseBidirectional>().as_mut(), prefix_suffix.as_mut())) } /// Analyzes whether a type is [`IntoBytes`]. diff --git a/src/pointer/inner.rs b/src/pointer/inner.rs index 5287ccb944..84a6bd4d18 100644 --- a/src/pointer/inner.rs +++ b/src/pointer/inner.rs @@ -89,7 +89,9 @@ mod _def { /// Rust allocation, `A`. /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live /// for at least `'a`. - pub(crate) const unsafe fn new(ptr: NonNull) -> PtrInner<'a, T> { + #[inline(always)] + #[must_use] + pub const unsafe fn new(ptr: NonNull) -> PtrInner<'a, T> { // SAFETY: The caller has promised to satisfy all safety invariants // of `PtrInner`. Self { ptr, _marker: PhantomData } @@ -160,6 +162,27 @@ impl<'a, T: ?Sized> PtrInner<'a, T> { // single allocated object. unsafe { Self::new(ptr) } } + + #[must_use] + #[inline(always)] + pub fn cast_sized(self) -> PtrInner<'a, U> + where + T: Sized, + { + static_assert!(T, U => size_of::() >= size_of::()); + let ptr = self.as_non_null().cast::(); + + // SAFETY: By the preceding assert, `U` is no larger than `T`. Thus, + // `ptr` addresses a subset of the bytes addressed by `self`. + // + // 0. By invariant on `self`, if `self`'s referent is not zero sized, + // then `self` has valid provenance for its referent, which is + // entirely contained in some Rust allocation, `A`. Thus, the same + // holds of `ptr`. + // 1. By invariant on `self`, if `self`'s referent is not zero sized, + // then `A` is guaranteed to live for at least `'a`. + unsafe { PtrInner::new(ptr) } + } } #[allow(clippy::needless_lifetimes)] diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 6005bc78f7..7c796e7cfe 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -18,7 +18,7 @@ mod transmute; pub use {inner::PtrInner, transmute::*}; #[doc(hidden)] pub use { - invariant::{BecauseExclusive, BecauseImmutable, Read}, + invariant::{BecauseExclusive, Read}, ptr::Ptr, }; @@ -30,11 +30,11 @@ pub type Maybe<'a, T, Aliasing = invariant::Shared, Alignment = invariant::Unali Ptr<'a, T, (Aliasing, Alignment, invariant::Initialized)>; /// Checks if the referent is zeroed. -pub(crate) fn is_zeroed(ptr: Ptr<'_, T, I>) -> bool +pub(crate) fn is_zeroed(mut ptr: Ptr<'_, T, I>) -> bool where T: crate::Immutable + crate::KnownLayout, I: invariant::Invariants, I::Aliasing: invariant::Reference, { - ptr.as_bytes::().as_ref().iter().all(|&byte| byte == 0) + ptr.reborrow().into_shared().as_bytes().as_ref().iter().all(|&byte| byte == 0) } diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index 375420f352..1231211117 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -9,14 +9,13 @@ use core::{ fmt::{Debug, Formatter}, marker::PhantomData, - ptr::NonNull, }; use crate::{ pointer::{ inner::PtrInner, invariant::*, - transmute::{MutationCompatible, SizeEq, TransmuteFromPtr}, + transmute::{MutationCompatible, SizeFrom, TransmuteFromPtr}, }, AlignmentError, CastError, CastType, KnownLayout, SizeError, TryFromBytes, ValidityError, }; @@ -74,32 +73,6 @@ mod def { T: 'a + ?Sized, I: Invariants, { - /// Constructs a `Ptr` from a [`NonNull`]. - /// - /// # Safety - /// - /// The caller promises that: - /// - /// 0. If `ptr`'s referent is not zero sized, then `ptr` has valid - /// provenance for its referent, which is entirely contained in some - /// Rust allocation, `A`. - /// 1. If `ptr`'s referent is not zero sized, `A` is guaranteed to live - /// for at least `'a`. - /// 2. `ptr` conforms to the aliasing invariant of - /// [`I::Aliasing`](invariant::Aliasing). - /// 3. `ptr` conforms to the alignment invariant of - /// [`I::Alignment`](invariant::Alignment). - /// 4. `ptr` conforms to the validity invariant of - /// [`I::Validity`](invariant::Validity). - pub(super) unsafe fn new(ptr: NonNull) -> Ptr<'a, T, I> { - // SAFETY: The caller has promised (in 0 - 1) to satisfy all safety - // invariants of `PtrInner::new`. - let ptr = unsafe { PtrInner::new(ptr) }; - // SAFETY: The caller has promised (in 2 - 4) to satisfy all safety - // invariants of `Ptr`. - Self { ptr, _invariants: PhantomData } - } - /// Constructs a new `Ptr` from a [`PtrInner`]. /// /// # Safety @@ -296,9 +269,8 @@ mod _conversions { { /// Reborrows `self`, producing another `Ptr`. /// - /// Since `self` is borrowed immutably, this prevents any mutable - /// methods from being called on `self` as long as the returned `Ptr` - /// exists. + /// Since `self` is borrowed mutably, this prevents `self` from being + /// used as long as the returned `Ptr` exists. #[doc(hidden)] #[inline] #[allow(clippy::needless_lifetimes)] // Allows us to name the lifetime in the safety comment below. @@ -339,6 +311,23 @@ mod _conversions { // memory may be live. unsafe { Ptr::from_inner(self.as_inner()) } } + + /// Converts `self` to a shared `Ptr`. + #[doc(hidden)] + #[inline] + #[allow(clippy::needless_lifetimes)] // Allows us to name the lifetime in the safety comment below. + pub fn into_shared(self) -> Ptr<'a, T, (Shared, I::Alignment, I::Validity)> { + // SAFETY: Since `I::Aliasing: Reference`, there are two cases for + // `I::Aliasing`: + // - For `invariant::Shared`, the returned `Ptr` is identical, so no + // new proof obligations are introduced. + // - For `invariant::Exclusive`: Since `self` has `Exclusive` + // aliasing, it is guaranteed that no other `Ptr`s or references + // permit concurrent access to the referent. Thus, the returned + // `Ptr` is the only reference to the referent which may read or + // write the referent during `'a`. + unsafe { self.assume_aliasing() } + } } /// `Ptr<'a, T>` → `&'a mut T` @@ -388,11 +377,11 @@ mod _conversions { pub(crate) fn transmute(self) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)> where V: Validity, - U: TransmuteFromPtr + SizeEq + ?Sized, + U: TransmuteFromPtr + SizeFrom + ?Sized, { // SAFETY: - // - `SizeEq::cast_from_raw` promises to preserve address, - // provenance, and the number of bytes in the referent + // - `SizeFrom::cast_from_raw` promises to preserve address and to + // address a prefix of the bytes addressed by its argument // - If aliasing is `Shared`, then by `U: TransmuteFromPtr`, at // least one of the following holds: // - `T: Immutable` and `U: Immutable`, in which case it is @@ -402,7 +391,7 @@ mod _conversions { // operate on these references simultaneously // - By `U: TransmuteFromPtr`, it is // sound to perform this transmute. - unsafe { self.transmute_unchecked(|ptr| SizeEq::cast_from_raw(ptr).as_non_null()) } + unsafe { self.transmute_unchecked(SizeFrom::cast_from_raw) } } #[doc(hidden)] @@ -420,7 +409,7 @@ mod _conversions { // referent simultaneously // - By `T: TransmuteFromPtr`, it is // sound to perform this transmute. - let ptr = unsafe { self.transmute_unchecked(|t| t.as_non_null()) }; + let ptr = unsafe { self.transmute_unchecked(SizeFrom::cast_from_raw) }; // SAFETY: `self` and `ptr` have the same address and referent type. // Therefore, if `self` satisfies `I::Alignment`, then so does // `ptr`. @@ -438,8 +427,7 @@ mod _conversions { /// /// The caller promises that `u = cast(p)` is a pointer cast with the /// following properties: - /// - `u` addresses a subset of the bytes addressed by `p` - /// - `u` has the same provenance as `p` + /// - `u` addresses a prefix of the bytes addressed by `p` /// - If `I::Aliasing` is [`Shared`], it must not be possible for safe /// code, operating on a `&T` and `&U` with the same referent /// simultaneously, to cause undefined behavior @@ -450,12 +438,6 @@ mod _conversions { /// `I::Aliasing`, `I::Validity`, and `V`, and may depend upon the /// presence, absence, or specific location of `UnsafeCell`s in `T` /// and/or `U`. See [`Validity`] for more details. - /// - /// `transmute_unchecked` guarantees that the pointer passed to `cast` - /// will reference a byte sequence which is either contained inside a - /// single allocated object or is zero sized. In either case, this means - /// that its size will fit in an `isize` and it will not wrap around the - /// address space. #[doc(hidden)] #[inline] pub unsafe fn transmute_unchecked( @@ -464,25 +446,18 @@ mod _conversions { ) -> Ptr<'a, U, (I::Aliasing, Unaligned, V)> where V: Validity, - F: FnOnce(PtrInner<'_, T>) -> NonNull, + F: FnOnce(PtrInner<'a, T>) -> PtrInner<'a, U>, { - // SAFETY: By invariant on `self`, `self.as_inner().as_non_null()` - // either references a zero-sized byte range, or else it references - // a byte range contained inside of a single allocated objection. let ptr = cast(self.as_inner()); // SAFETY: // - // Lemma 1: `ptr` has the same provenance as `self`. The caller - // promises that `cast` preserves provenance, and we call it with - // `self.as_inner().as_non_null()`. + // The following safety arguments rely on the fact that the caller + // promises that `cast` returns a `PtrInner` which addresses a + // prefix of the bytes of `*self`, and so properties that hold of + // `*self` also hold of `*ptr`. // - // 0. By invariant, if `self`'s referent is not zero sized, then - // `self` has valid provenance for its entire referent, which is - // entirely contained in `A`. By Lemma 1, so does `ptr`. - // 1. By invariant on `self`, if `self`'s referent is not zero - // sized, then `A` is guaranteed to live for at least `'a`. - // 2. `ptr` conforms to the aliasing invariant of `I::Aliasing`: + // 0. `ptr` conforms to the aliasing invariant of `I::Aliasing`: // - `Exclusive`: `self` is the only `Ptr` or reference which is // permitted to read or modify the referent for the lifetime // `'a`. Since we consume `self` by value, the returned pointer @@ -499,10 +474,10 @@ mod _conversions { // of `UnsafeCell`s is unsound, this must be impossible using // `&T` and `&U`. // - `Inaccessible`: There are no restrictions we need to uphold. - // 3. `ptr` trivially satisfies the alignment invariant `Unaligned`. - // 4. The caller promises that `ptr` conforms to the validity + // 1. `ptr` trivially satisfies the alignment invariant `Unaligned`. + // 2. The caller promises that `ptr` conforms to the validity // invariant `V` with respect to its referent type, `U`. - unsafe { Ptr::new(ptr) } + unsafe { Ptr::from_inner(ptr) } } } @@ -535,7 +510,7 @@ mod _conversions { // validity of the other. let ptr = unsafe { #[allow(clippy::as_conversions)] - self.transmute_unchecked(|ptr| ptr.as_non_null().cast::>()) + self.transmute_unchecked(|p| p.cast_sized::>()) }; ptr.bikeshed_recall_aligned() } @@ -858,9 +833,13 @@ mod _transitions { // SAFETY: If `T::is_bit_valid`, code may assume that `self` // contains a bit-valid instance of `T`. By `T: // TryTransmuteFromPtr`, so - // long as `self`'s referent conforms to the `Valid` validity - // for `T` (which we just confired), then this transmute is - // sound. + // long as `SizeFrom::cast_from_raw(self.into_inner)`'s referent + // conforms to the `Valid` validity for `T`, then this transmute + // is sound. Since `>::cast_from_raw` is + // guaranteed to be the identity function, this is equivalent to + // the statement that `self`'s referent conforms to the `Valid` + // validity for `T`, which we just confirmed using + // `T::is_bit_valid`. Ok(unsafe { self.assume_valid() }) } else { Err(ValidityError::new(self)) @@ -911,7 +890,7 @@ mod _casts { /// around the address space. #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized_unchecked) -> NonNull>( + pub unsafe fn cast_unsized_unchecked) -> PtrInner<'a, U>>( self, cast: F, ) -> Ptr<'a, U, (I::Aliasing, Unaligned, I::Validity)> @@ -957,9 +936,11 @@ mod _casts { cast: F, ) -> Ptr<'a, U, (I::Aliasing, Unaligned, I::Validity)> where - T: MutationCompatible, - U: 'a + ?Sized + CastableFrom, - F: FnOnce(PtrInner<'_, T>) -> NonNull, + U: 'a + + MutationCompatible + + CastableFrom + + ?Sized, + F: FnOnce(PtrInner<'_, T>) -> PtrInner<'_, U>, { // SAFETY: Because `T: MutationCompatible`, one // of the following holds: @@ -984,7 +965,7 @@ mod _casts { #[allow(clippy::wrong_self_convention)] pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> where - T: Read, + [u8]: MutationCompatible, I::Aliasing: Reference, { let bytes = match T::size_of_val_raw(self.as_inner().as_non_null()) { @@ -1010,12 +991,15 @@ mod _casts { ); // SAFETY: `ptr` has the same address as `p`, which is // non-null. - core::ptr::NonNull::new_unchecked(ptr) + let ptr = core::ptr::NonNull::new_unchecked(ptr); + + // TODO: SAFETY + PtrInner::new(ptr) }) }; let ptr = ptr.bikeshed_recall_aligned(); - ptr.recall_validity::<_, (_, (_, _))>() + ptr.recall_validity::() } } @@ -1100,7 +1084,8 @@ mod _casts { > where I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + Read, + U: 'a + ?Sized + KnownLayout, + [u8]: MutationCompatible, { let (inner, remainder) = self.as_inner().try_cast_into(cast_type, meta).map_err(|err| { @@ -1163,7 +1148,8 @@ mod _casts { ) -> Result, CastError> where I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + Read, + U: 'a + ?Sized + KnownLayout, + [u8]: MutationCompatible, { // FIXME(#67): Remove this allow. See NonNulSlicelExt for more // details. @@ -1234,7 +1220,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(|ptr| cast!(ptr).as_non_null()) }; + let ptr = unsafe { self.transmute_unchecked(|ptr| cast!(ptr)) }; // SAFETY: `UnsafeCell` has the same alignment as `T` [1], // and so if `self` is guaranteed to be aligned, then so is the @@ -1295,7 +1281,7 @@ mod tests { use super::*; #[allow(unused)] // Needed on our MSRV, but considered unused on later toolchains. use crate::util::AsAddress; - use crate::{pointer::BecauseImmutable, util::testutil::AU64, FromBytes, Immutable}; + use crate::{pointer::invariant::BecauseImmutable, util::testutil::AU64, FromBytes, Immutable}; mod test_ptr_try_cast_into_soundness { use super::*; diff --git a/src/pointer/transmute.rs b/src/pointer/transmute.rs index 1fa0540526..79fb8774ec 100644 --- a/src/pointer/transmute.rs +++ b/src/pointer/transmute.rs @@ -13,7 +13,7 @@ use core::{ }; use crate::{ - pointer::{invariant::*, PtrInner}, + pointer::{inner::PtrInner, invariant::*}, FromBytes, Immutable, IntoBytes, Unalign, }; @@ -33,42 +33,43 @@ use crate::{ /// Given `Dst: TryTransmuteFromPtr`, callers may assume the /// following: /// -/// Given `src: Ptr<'a, Src, (A, _, SV)>`, if the referent of `src` is -/// `DV`-valid for `Dst`, then it is sound to transmute `src` into `dst: Ptr<'a, -/// Dst, (A, Unaligned, DV)>` by preserving pointer address and metadata. +/// Given `src: Ptr<'a, Src, (A, _, SV)>` and `dst_inner = +/// SizeFrom::cast_from_raw(src.into_inner())`, if the referent of `dst_inner` +/// is `DV`-valid for `Dst`, then it is sound to construct `dst: Ptr<'a, Dst, +/// (A, Unaligned, DV)>` from `dst_inner`. Equivalently, it is sound to +/// transmute `src` into `dst` using [`SizeFrom::cast_from_raw`]. /// /// ## Pre-conditions /// -/// Given `src: Ptr` and `dst: Ptr`, -/// `Dst: TryTransmuteFromPtr` is sound if all of the -/// following hold: +/// Given `src: Ptr` and `dst: Ptr` +/// constructed from `SizeFrom::cast_from_raw(src.into_inner())`, `Dst: +/// TryTransmuteFromPtr` is sound if all of the following +/// hold: /// - Forwards transmutation: Either 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 +/// - `Dst: TransmuteFrom` /// - Reverse transmutation: Either 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 +/// - `Src: TransmuteFrom` /// - No safe code, given access to `src` and `dst`, can cause undefined /// behavior: Any of the following hold: /// - `A` is `Exclusive` /// - `Src: Immutable` and `Dst: Immutable` -/// - It is sound for shared code to operate on a `&Src` and `&Dst` which -/// reference the same byte range at the same time +/// - It is sound for safe code to operate on `src.as_ref(): &Src` and +/// `dst.as_ref(): &Dst` at the same time /// /// ## Proof /// /// Given: /// - `src: Ptr<'a, Src, (A, _, SV)>` -/// - `src`'s referent is `DV`-valid for `Dst` -/// - `Dst: SizeEq` +/// - The leading `N` bytes of `src`'s referent are a `DV`-valid `Dst`, where +/// `N` is the referent size of `SizeFrom::cast_from_raw(src)` /// -/// We are trying to prove that it is sound to perform a pointer address- and -/// metadata-preserving transmute from `src` to a `dst: Ptr<'a, Dst, (A, -/// Unaligned, DV)>`. We need to prove that such a transmute does not violate -/// any of `src`'s invariants, and that it satisfies all invariants of the -/// destination `Ptr` type. +/// We are trying to prove that it is sound to use `SizeFrom::cast_from_raw` to +/// transmute from `src` to a `dst: Ptr<'a, Dst, (A, Unaligned, DV)>`. We need +/// to prove that such a transmute does not violate any of `src`'s invariants, +/// and that it satisfies all invariants of the destination `Ptr` type. /// /// First, all of `src`'s `PtrInner` invariants are upheld. `src`'s address and /// metadata are unchanged, so: @@ -78,16 +79,16 @@ use crate::{ /// - If its referent is not zero sized, `A` is guaranteed to live for at least /// `'a` /// -/// Since `Dst: SizeEq`, and since `dst` has the same address and metadata -/// as `src`, `dst` addresses the same byte range as `src`. `dst` also has the -/// same lifetime as `src`. Therefore, all of the `PtrInner` invariants -/// mentioned above also hold for `dst`. +/// By post-condition on `SizeFrom::cast_from_raw`, `dst` addresses a prefix of +/// the bytes addressed by `src`. `dst` also has the same lifetime as `src`. +/// Therefore, all of the `PtrInner` invariants mentioned above also hold for +/// `dst`. /// /// Second, since `src`'s address is unchanged, it still satisfies its /// alignment. Since `dst`'s alignment is `Unaligned`, it trivially satisfies /// its alignment. /// -/// Third, aliasing is either `Exclusive` or `Shared`: +/// Third, aliasing (`A`) is either `Exclusive` or `Shared`: /// - If it is `Exclusive`, then both `src` and `dst` satisfy `Exclusive` /// aliasing trivially: since `src` and `dst` have the same lifetime, `src` is /// inaccessible so long as `dst` is alive, and no other live `Ptr`s or @@ -95,79 +96,42 @@ use crate::{ /// - If it is `Shared`, then either: /// - `Src: Immutable` and `Dst: Immutable`, and so `UnsafeCell`s trivially /// cover the same byte ranges in both types. -/// - It is explicitly sound for safe code to operate on a `&Src` and a `&Dst` -/// pointing to the same byte range at the same time. +/// - It is sound for safe code to operate on a `src.as_ref()` and +/// `dst.as_ref()` at the same time. /// /// Fourth, `src`'s validity is satisfied. By invariant, `src`'s referent began /// as an `SV`-valid `Src`. It is guaranteed to remain so, as either of the /// following hold: /// - `dst` does not permit mutation of its referent. -/// - The set of `DV`-valid `Dst`s is a superset of the set of `SV`-valid -/// `Src`s. Thus, any value written via `dst` is guaranteed to be `SV`-valid -/// for `Src`. +/// - `Src: TransmuteFrom`. Since `Dst: SizeFrom`, and since +/// `dst` is produced using `SizeFrom::cast_from_raw`, given `src'` composed +/// by concatenating any `DV`-valid `Dst` of size `size_of_val(dst)` with the +/// trailing `size_of_val(src) - size_of_val(dst)` bytes of `src`, `src'` is +/// an `SV`-valid `Src`. Thus, any value written to `dst` is guaranteed not to +/// violate the `SV`-validity of `Src`. /// /// Fifth, `dst`'s validity is satisfied. It is a given of this proof that the -/// referent is `DV`-valid for `Dst`. It is guaranteed to remain so, as either -/// of the following hold: +/// leading bytes of the referent are `DV`-valid for `Dst`. It is guaranteed to +/// remain so, as either of the following hold: /// - So long as `dst` is active, no mutation of the 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. Thus, any value written via `src` is guaranteed to be a `DV`-valid -/// `Dst`. +/// - `Dst: TransmuteFrom`. Since `Dst: SizeFrom`, and since +/// `dst` is produced using `SizeFrom::cast_from_raw`, the leading +/// `size_of_val(dst)` bytes of any `SV`-valid `Src` constitute a `DV`-valid +/// `Dst`. Thus, any value written via `src` is guaranteed not to violate the +/// `DV`-validity of `Dst`. pub unsafe trait TryTransmuteFromPtr: - SizeEq + SizeFrom { } -#[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum BecauseMutationCompatible {} - -// SAFETY: -// - Forwards transmutation: By `Dst: MutationCompatible`, we -// know that at least one of the following holds: -// - So long as `dst: Ptr` is active, no mutation of its referent is -// allowed except via `dst` itself if either of the following hold: -// - Aliasing is `Exclusive`, in which case, so long as the `Dst` `Ptr` -// exists, no mutation is permitted except via that `Ptr` -// - Aliasing is `Shared`, `Src: Immutable`, and `Dst: Immutable`, in which -// case no mutation is possible via either `Ptr` -// - `Dst: TransmuteFrom`. Since `Dst: SizeEq`, this bound -// guarantees that the set of `DV`-valid `Dst`s is a supserset of the set of -// `SV`-valid `Src`s. -// - Reverse transmutation: `Src: TransmuteFrom`. Since `Dst: -// SizeEq`, this guarantees that the set of `DV`-valid `Dst`s is a subset -// of the set of `SV`-valid `Src`s. -// - No safe code, given access to `src` and `dst`, can cause undefined -// behavior: By `Dst: MutationCompatible`, at least one of -// the following holds: -// - `A` is `Exclusive` -// - `Src: Immutable` and `Dst: Immutable` -// - `Dst: InvariantsEq`, which guarantees that `Src` and `Dst` have the -// same invariants, and have `UnsafeCell`s covering the same byte ranges -unsafe impl - TryTransmuteFromPtr for Dst +unsafe impl TryTransmuteFromPtr for Dst where A: Aliasing, SV: Validity, DV: Validity, - Src: TransmuteFrom + ?Sized, - Dst: MutationCompatible + SizeEq + ?Sized, -{ -} - -// SAFETY: -// - Forwards transmutation: Since aliasing is `Shared` and `Src: Immutable`, -// `src` does not permit mutation of its referent. -// - Reverse transmutation: Since aliasing is `Shared` and `Dst: Immutable`, -// `dst` does not permit mutation of its referent. -// - No safe code, given access to `src` and `dst`, can cause undefined -// behavior: `Src: Immutable` and `Dst: Immutable` -unsafe impl TryTransmuteFromPtr for Dst -where - SV: Validity, - DV: Validity, - Src: Immutable + ?Sized, - Dst: Immutable + SizeEq + ?Sized, + Src: ?Sized, + Dst: MutationCompatible + SizeFrom + ?Sized, { } @@ -178,21 +142,38 @@ where /// # Safety /// /// At least one of the following must hold: -/// - `Src: Read` and `Self: Read` -/// - `Self: InvariantsEq`, and, for some `V`: -/// - `Dst: TransmuteFrom` -/// - `Src: TransmuteFrom` +/// - `A = Exclusive` and `Src: TransmuteFromTear` +/// - `A = Shared`, `Src: Immutable`, and `Dst: Immutable` +/// - `A = Shared`, `Dst: TransmuteFromShrink`, `Src: +/// TransmuteFromTear`, and `Dst: InvariantsEq` pub unsafe trait MutationCompatible {} #[allow(missing_copy_implementations, missing_debug_implementations)] -pub enum BecauseRead {} +pub enum BecauseReversible {} + +#[allow(missing_copy_implementations, missing_debug_implementations)] +pub enum BecauseBidirectional {} + +unsafe impl + MutationCompatible for Dst +where + Src: TransmuteOverwrite, +{ +} + +unsafe impl + MutationCompatible for Dst +where + Src: Immutable, + Dst: Immutable, +{ +} -// SAFETY: `Src: Read` and `Dst: Read`. -unsafe impl - MutationCompatible for Dst +unsafe impl + MutationCompatible for Dst where - Src: Read, - Dst: Read, + Dst: TransmuteFrom + InvariantsEq, + Src: TransmuteOverwrite, { } @@ -208,18 +189,6 @@ pub unsafe trait InvariantsEq {} // SAFETY: Trivially sound to have multiple `&T` pointing to the same referent. unsafe impl InvariantsEq for T {} -// SAFETY: `Dst: InvariantsEq + TransmuteFrom`, and `Src: -// TransmuteFrom`. -unsafe impl - MutationCompatible for Dst -where - Src: TransmuteFrom, - Dst: TransmuteFrom + InvariantsEq, -{ -} - -pub(crate) enum BecauseInvariantsEq {} - macro_rules! unsafe_impl_invariants_eq { ($tyvar:ident => $t:ty, $u:ty) => {{ crate::util::macros::__unsafe(); @@ -250,13 +219,22 @@ unsafe impl InvariantsEq> for T {} /// Transmutations which are always sound. /// -/// `TransmuteFromPtr` is a shorthand for [`TryTransmuteFromPtr`] and -/// [`TransmuteFrom`]. +/// `TransmuteFromPtr` is a shorthand for the conjuction of +/// [`TryTransmuteFromPtr`] and [`TransmuteFrom`]. /// /// # Safety /// /// `Dst: TransmuteFromPtr` is equivalent to `Dst: /// TryTransmuteFromPtr + TransmuteFrom`. +/// +/// Further, if `Dst: TransmuteFromPtr`, then given `src: +/// Ptr<'_, (A, _, SV)>`, it is sound to transmute `src` to `dst: Ptr<'_, (A, _, +/// DV)>` using [`SizeFrom::cast_from_raw`] to perform the raw pointer +/// transmute. +/// +/// ## Proof +/// +/// TODO pub unsafe trait TransmuteFromPtr: TryTransmuteFromPtr + TransmuteFrom { @@ -276,43 +254,74 @@ where /// /// # Safety /// -/// Given `src: Ptr` and `dst: Ptr`, if the -/// referents of `src` and `dst` are the same size, then the set of bit patterns -/// allowed to appear in `src`'s referent must be a subset of the set allowed to -/// appear in `dst`'s referent. +/// *In this section, we refer to `Self` as `Dst`.* +/// +/// If `Dst: SizeFrom` (or `Dst: Sized` and `Src: Sized` where +/// `size_of::() <= size_of::()`), then the following must hold: For +/// all [valid sizes] of `Src` (or for `size_of::()`), `ssize`, let `s: +/// PtrInner<'_, Src>` with referent size `ssize`. Let `dsize` be the referent +/// size of `SizeFrom::cast_from_raw(s)` (or `size_of::()`). Note that, by +/// invariant on `cast_from_raw` (or by `size_of::() <= size_of::()`), +/// `ssize >= dsize`. For all `SV`-valid values of `Src` with size `ssize`, +/// `src`, it must be the case that the leading `dsize` bytes of `src` +/// constitute a `DV`-valid `Dst`. /// -/// If the referents are not the same size, then `Dst: TransmuteFrom` conveys no safety guarantee. +/// [valid sizes]: crate::KnownLayout#what-is-a-valid-size pub unsafe trait TransmuteFrom {} +/// Denotes that any `BV`-valid `Self` may have its prefix overwritten with any +/// `OV`-valid `Overlay` and remain `BV`-valid. +/// /// # 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: PtrInner<'_, T>`, `>::cast_from_raw(t)` produces -/// a pointer which addresses the same number of bytes as `t`. *Note that it -/// is **not** guaranteed that an `as` cast preserves referent size: it may be -/// the case that `cast_from_raw` modifies the pointer's metadata in order to -/// preserve referent size, which an `as` cast does not do.* -pub unsafe trait SizeEq { - fn cast_from_raw(t: PtrInner<'_, T>) -> PtrInner<'_, Self>; +/// *In this section, we refer to `Self` as `Base`.* +/// +/// If `Overlay: SizeFrom`, then the following must hold: For all [valid +/// sizes] of `Base`, `bsize`, let `b: PtrInner<'_, Base>` with referent size +/// `bsize`. Let `osize` be the referent size of `SizeFrom::cast_from_raw(b)`. +/// Note that, by invariant on `cast_from_raw`, `bsize >= osize`. For all +/// `BV`-valid values of `Base` with size `bsize`, `base`, and for all +/// `OV`-valid values of `Overlay` with size `osize`, `overlay`, let `base'` be +/// constructed by concatenating `overlay` with the trailing `bsize - osize` +/// bytes of `base`. It must be the case that `base'` is a `BV`-valid `Base`. +/// +/// [valid sizes]: crate::KnownLayout#what-is-a-valid-size +pub unsafe trait TransmuteOverwrite {} + +/// # Safety +/// +/// Implementations of `cast_from_raw` must satisfy that method's safety +/// post-condition. +pub unsafe trait SizeFrom { + /// # Safety + /// + /// Given `src: PtrInner<'_, Src>`, `let dst = Self::cast_from_raw(src)` + /// produces a pointer with the same address as `src`, and referring to at + /// most as many bytes. If `src` has valid provenance for its referent, then + /// `dst` has valid provenance for *its* referent. + /// + /// The size of `dst` must only be a function of the size of `src`. It must + /// not be a function of `src`'s address. + /// + /// `>::cast_from_raw` is guaranteed to be the + /// identity function. + fn cast_from_raw(src: PtrInner<'_, Src>) -> PtrInner<'_, Self>; } // 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 { +unsafe impl SizeFrom for T { #[inline(always)] - fn cast_from_raw(t: PtrInner<'_, T>) -> PtrInner<'_, T> { + fn cast_from_raw<'a>(t: PtrInner<'a, T>) -> PtrInner<'a, T> { t } } +/// `Valid → Initialized` // 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`. +// any `Initialized` `Ptr`. This holds even for shrinking transmutes. unsafe impl TransmuteFrom for Dst where Src: IntoBytes + ?Sized, @@ -320,9 +329,24 @@ where { } -// 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`. +/// `Valid → Initialized` +// SAFETY: Let `overlay` be a `Valid` `Overlay` and `base` be an `Initialized` +// `Base`. The trailing bytes of `base` have bit validity `[u8; N]`. By +// `Overlay: IntoBytes`, `overlay`'s bit validity is at least as restrictive as +// `[u8; M]` (some `[u8; M]` values may not be valid `Overlay` values). Thus, +// `base' = overlay + trailing_bytes_of(base)` is a valid `[u8; N + M]`, which +// is a valid `Initialized` value. +unsafe impl TransmuteOverwrite for Base +where + Overlay: IntoBytes + ?Sized, + Base: ?Sized, +{ +} + +/// `Initialized → Valid` +// SAFETY: Since `Dst: FromBytes`, any initialized bit pattern is a valid `Dst`. +// An `Initialized` is guaranteed to have all its bytes initialized, so any +// (prefix of an) `Initialized` is a valid `Dst`. unsafe impl TransmuteFrom for Dst where Src: ?Sized, @@ -330,12 +354,26 @@ where { } +/// `Initialized → Valid` +// SAFETY: The bit validity of `Initialized` is equivalent to that of +// `[u8]`. By `Base: FromBytes + IntoBytes`, the validity of `Valid` is +// also equivalent to that of `[u8]`. Any two `[u8]`s concatenated together are +// a valid `[u8]`. +unsafe impl TransmuteOverwrite for Base +where + Overlay: ?Sized, + Base: FromBytes + IntoBytes + ?Sized, +{ +} + // FIXME(#2354): 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. +/// `Initialized → Initialized` +// SAFETY: The validity of `Initialized` is equal to that of `[u8]`. `[u8]`'s +// validity does not depend on a value's length, so any prefix of an +// `Initialized` is a valid `Initialized`. unsafe impl TransmuteFrom for Dst where Src: ?Sized, @@ -343,12 +381,25 @@ where { } +/// `Initialized → Initialized` +// SAFETY: The validity of `Initialized` is equal to that of `[u8]`. `[u8]`'s +// validity does not depend on a value's length, so two `[u8]`s concatenated +// together are also a valid `[u8]`. Thus, an `Initialized` +// concatenated with the `[u8]` suffix of an `Initialized` is a valid +// `Initialized`. +unsafe impl TransmuteOverwrite for Base +where + Overlay: ?Sized, + Base: ?Sized, +{ +} + // FIXME(#2354): This seems like a smell - the soundness of this bound has // nothing to do with `Dst` - we're basically just saying that any type is // transmutable into `MaybeUninit<[u8; N]>`. -// SAFETY: A `Dst` with validity `Uninit` permits any byte sequence, and -// therefore can be transmuted from any value. +/// `V → Uninit` +// SAFETY: A `Dst` with validity `Uninit` permits any byte sequence. unsafe impl TransmuteFrom for Dst where Src: ?Sized, @@ -357,6 +408,16 @@ where { } +/// `V → Uninit` +// SAFETY: A `Base` with validity `Uninit` permits any byte sequence. +unsafe impl TransmuteOverwrite for Base +where + Overlay: ?Sized, + Base: ?Sized, + V: Validity, +{ +} + // SAFETY: // - `ManuallyDrop` has the same size as `T` [1] // - `ManuallyDrop` has the same validity as `T` [1] @@ -447,19 +508,25 @@ const _: () = unsafe { unsafe_impl_for_transparent_wrapper!(T: ?Sized => Cell impl_transitive_transmute_from!(T: ?Sized => Cell => T => UnsafeCell); impl_transitive_transmute_from!(T: ?Sized => UnsafeCell => T => Cell); +/// `Uninit → Valid>` // 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 {} +unsafe impl TransmuteFrom for MaybeUninit {} + +/// `Uninit → Valid>` +// SAFETY: See previous safety comment. +unsafe impl TransmuteOverwrite for MaybeUninit {} -// SAFETY: `MaybeUninit` has the same size as `T` [1]. +// SAFETY: `MaybeUninit` has the same size as `T` [1]. Thus, a pointer cast +// preserves address and referent size. // // [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 { +unsafe impl SizeFrom for MaybeUninit { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, T>) -> PtrInner<'_, MaybeUninit> { // SAFETY: Per preceding safety comment, `MaybeUninit` and `T` have @@ -469,7 +536,7 @@ unsafe impl SizeEq for MaybeUninit { } // SAFETY: See previous safety comment. -unsafe impl SizeEq> for T { +unsafe impl SizeFrom> for T { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, MaybeUninit>) -> PtrInner<'_, T> { // SAFETY: Per preceding safety comment, `MaybeUninit` and `T` have diff --git a/src/ref.rs b/src/ref.rs index 423bf84988..a428168ff6 100644 --- a/src/ref.rs +++ b/src/ref.rs @@ -656,9 +656,9 @@ where // `b.into_byte_slice_mut()` produces a byte slice with identical // address and length to that produced by `b.deref_mut()`. let ptr = Ptr::from_mut(b.into_byte_slice_mut()) - .try_cast_into_no_leftover::(None) + .try_cast_into_no_leftover(None) .expect("zerocopy internal error: into_ref should be infallible"); - let ptr = ptr.recall_validity::<_, (_, (_, _))>(); + let ptr = ptr.recall_validity::<_, BecauseBidirectional>(); ptr.as_mut() } } @@ -797,9 +797,9 @@ where // are preserved through `.deref_mut()`, so this `unwrap` will not // panic. let ptr = Ptr::from_mut(b.deref_mut()) - .try_cast_into_no_leftover::(None) + .try_cast_into_no_leftover(None) .expect("zerocopy internal error: DerefMut::deref_mut should be infallible"); - let ptr = ptr.recall_validity::<_, (_, (_, (BecauseExclusive, BecauseExclusive)))>(); + let ptr = ptr.recall_validity::<_, BecauseBidirectional>(); ptr.as_mut() } } diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index 4e331062fc..f1f2bc4247 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -30,8 +30,8 @@ use core::ptr::{self, NonNull}; use crate::{ pointer::{ - invariant::{self, BecauseExclusive, BecauseImmutable, Invariants}, - BecauseInvariantsEq, InvariantsEq, SizeEq, TryTransmuteFromPtr, + invariant::{self, BecauseImmutable, Invariants}, + BecauseBidirectional, InvariantsEq, MutationCompatible, SizeFrom, TryTransmuteFromPtr, }, FromBytes, FromZeros, Immutable, IntoBytes, KnownLayout, Ptr, TryFromBytes, ValidityError, }; @@ -502,10 +502,11 @@ fn try_cast_or_pme( where // FIXME(#2226): There should be a `Src: FromBytes` bound here, but doing so // requires deeper surgery. - Src: invariant::Read, + Src: MutationCompatible, Dst: TryFromBytes - + invariant::Read - + TryTransmuteFromPtr, + + invariant::Read + + MutationCompatible + + TryTransmuteFromPtr, I: Invariants, I::Aliasing: invariant::Reference, { @@ -516,8 +517,7 @@ where // because we assert above that the size of `Dst` equal to the size of // `Src`. // - `p as *mut Dst` is a provenance-preserving cast - #[allow(clippy::as_conversions)] - let c_ptr = unsafe { src.cast_unsized(|ptr| ptr.as_non_null().cast::()) }; + let c_ptr = unsafe { src.cast_unsized(|p| cast!(p)) }; match c_ptr.try_into_valid() { Ok(ptr) => Ok(ptr), @@ -530,8 +530,7 @@ where // `ptr`, because we assert above that the size of `Dst` is equal // to the size of `Src`. // - `p as *mut Src` is a provenance-preserving cast - #[allow(clippy::as_conversions)] - let ptr = unsafe { ptr.cast_unsized(|ptr| ptr.as_non_null().cast::()) }; + let ptr = unsafe { ptr.cast_unsized(|p| cast!(p)) }; // 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. @@ -586,7 +585,7 @@ where // ABI as `T` let ptr: Ptr<'_, Dst, _> = unsafe { ptr.cast_unsized(|ptr: crate::pointer::PtrInner<'_, mem::MaybeUninit>| { - ptr.as_non_null().cast() + ptr.cast_sized() }) }; @@ -666,7 +665,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 @@ -675,7 +674,7 @@ where Ok(ptr.as_mut()) } Err(err) => { - Err(err.map_src(|ptr| ptr.recall_validity::<_, (_, BecauseInvariantsEq)>().as_mut())) + Err(err.map_src(|ptr| ptr.recall_validity::<_, BecauseBidirectional>().as_mut())) } } } @@ -795,11 +794,11 @@ where // SAFETY: We only use `S` as `S` and `D` as `D`. unsafe { - unsafe_with_size_eq!(, D> { + unsafe_with_size_from!(, D> { let ptr = Ptr::from_ref(self.0) - .transmute::, invariant::Valid, BecauseImmutable>() + .transmute::, invariant::Valid, _>() .recall_validity::() - .transmute::, invariant::Initialized, (crate::pointer::BecauseMutationCompatible, _)>() + .transmute::, invariant::Initialized, _>() .recall_validity::(); #[allow(unused_unsafe)] @@ -835,12 +834,12 @@ where // SAFETY: We only use `S` as `S` and `D` as `D`. unsafe { - unsafe_with_size_eq!(, D> { + unsafe_with_size_from!(, D> { let ptr = Ptr::from_mut(self.0) .transmute::, invariant::Valid, _>() - .recall_validity::() + .recall_validity::() .transmute::, invariant::Initialized, _>() - .recall_validity::(); + .recall_validity::(); #[allow(unused_unsafe)] // SAFETY: The preceding `static_assert!` ensures that diff --git a/src/util/macros.rs b/src/util/macros.rs index 78a4ebf2ac..51b1a9fe04 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -220,7 +220,7 @@ macro_rules! impl_for_transmute_from { #[inline] 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)))>(); + let c: Maybe<'_, $repr, _> = c.transmute(); // SAFETY: This macro ensures that `$repr` and `Self` have the same // size and bit validity. Thus, a bit-valid instance of `$repr` is // also a bit-valid instance of `Self`. @@ -677,22 +677,21 @@ macro_rules! static_assert_dst_is_not_zst { }} } +/// # Safety +/// +/// The caller must ensure that the cast does not grow the size of the referent. +/// Preserving or shrinking the size of the referent are both acceptable. macro_rules! cast { - () => { - |p| { - // SAFETY: `NonNull::as_ptr` returns a non-null pointer, so the - // argument to `NonNull::new_unchecked` is also non-null. - #[allow(clippy::as_conversions, unused_unsafe)] - #[allow(clippy::undocumented_unsafe_blocks)] // Clippy false positive - return unsafe { - core::ptr::NonNull::new_unchecked(core::ptr::NonNull::as_ptr(p) as *mut _) - }; - } - }; ($p:expr) => {{ let ptr: crate::pointer::PtrInner<'_, _> = $p; let ptr = ptr.as_non_null(); - let ptr = cast!()(ptr); + let ptr = ptr.as_ptr(); + #[allow(clippy::as_conversions)] + let ptr = ptr as *mut _; + #[allow(unused_unsafe)] + // SAFETY: `NonNull::as_ptr` returns a non-null pointer, so the argument + // to `NonNull::new_unchecked` is also non-null. + let ptr = unsafe { core::ptr::NonNull::new_unchecked(ptr) }; // SAFETY: The caller promises that the cast preserves or shrinks // referent size. By invariant on `$p: PtrInner` (guaranteed by type // annotation above), `$p` refers to a byte range entirely contained @@ -703,37 +702,42 @@ macro_rules! cast { }}; } -/// Implements `TransmuteFrom` and `SizeEq` for `T` and `$wrapper`. +/// Implements `TransmuteFrom` and `SizeFrom` 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`. +/// `T` and `$wrapper` must have the same bit validity, and must satisfy the +/// following property: given `t: *mut T`, `let w = t as *mut $wrapper` +/// produces a pointer which address the same bytes as `t`. The inverse must +/// also hold. macro_rules! unsafe_impl_for_transparent_wrapper { (T $(: ?$optbound:ident)? => $wrapper:ident) => {{ crate::util::macros::__unsafe(); - use crate::pointer::{TransmuteFrom, PtrInner, SizeEq, invariant::Valid}; + use crate::pointer::{TransmuteFrom, TransmuteOverwrite, PtrInner, SizeFrom, invariant::Valid}; // SAFETY: The caller promises that `T` and `$wrapper` have the same - // bit validity. + // bit validity, and that both implementations of + // `SizeFrom::cast_from_raw` preserve referent size exactly. unsafe impl TransmuteFrom for $wrapper {} // SAFETY: See previous safety comment. unsafe impl TransmuteFrom<$wrapper, Valid, Valid> for T {} + // SAFETY: See previous safety comment. + unsafe impl TransmuteOverwrite for $wrapper {} + // SAFETY: See previous safety comment. + unsafe impl TransmuteOverwrite<$wrapper, Valid, Valid> for T {} // SAFETY: The caller promises that `T` and `$wrapper` satisfy - // `SizeEq`. - unsafe impl SizeEq for $wrapper { + // `cast_from_raw`'s safety post-condition. + unsafe impl SizeFrom for $wrapper { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, T>) -> PtrInner<'_, $wrapper> { - // SAFETY: See previous safety comment. unsafe { cast!(t) } } } // SAFETY: See previous safety comment. - unsafe impl SizeEq<$wrapper> for T { + unsafe impl SizeFrom<$wrapper> for T { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, $wrapper>) -> PtrInner<'_, T> { - // SAFETY: See previous safety comment. unsafe { cast!(t) } } } @@ -743,19 +747,20 @@ macro_rules! unsafe_impl_for_transparent_wrapper { macro_rules! impl_transitive_transmute_from { ($($tyvar:ident $(: ?$optbound:ident)?)? => $t:ty => $u:ty => $v:ty) => { const _: () = { - use crate::pointer::{TransmuteFrom, PtrInner, SizeEq, invariant::Valid}; + use crate::pointer::{TransmuteFrom, SizeFrom, invariant::Valid}; - // SAFETY: Since `$u: SizeEq<$t>` and `$v: SizeEq`, this impl is - // transitively sound. - unsafe impl<$($tyvar $(: ?$optbound)?)?> SizeEq<$t> for $v + // SAFETY: See safety comment on `cast_from_raw`. + unsafe impl<$($tyvar $(: ?$optbound)?)?> SizeFrom<$t> for $v where - $u: SizeEq<$t>, - $v: SizeEq<$u>, + $u: SizeFrom<$t>, + $v: SizeFrom<$u>, { + // SAFETY: Each inner call to `cast_from_raw` preserves + // provenance and addressed byte range. #[inline(always)] fn cast_from_raw(t: PtrInner<'_, $t>) -> PtrInner<'_, $v> { - let u = <$u as SizeEq<_>>::cast_from_raw(t); - <$v as SizeEq<_>>::cast_from_raw(u) + let u = SizeFrom::cast_from_raw(t); + SizeFrom::cast_from_raw(u) } } @@ -773,10 +778,10 @@ macro_rules! impl_transitive_transmute_from { } #[rustfmt::skip] -macro_rules! impl_size_eq { +macro_rules! impl_size_from { ($t:ty, $u:ty) => { const _: () = { - use crate::{KnownLayout, pointer::{PtrInner, SizeEq}}; + use crate::{KnownLayout, pointer::{PtrInner, SizeFrom}}; static_assert!(=> { let t = <$t as KnownLayout>::LAYOUT; @@ -792,7 +797,7 @@ macro_rules! impl_size_eq { }); // SAFETY: See inline. - unsafe impl SizeEq<$t> for $u { + unsafe impl SizeFrom<$t> for $u { #[inline(always)] fn cast_from_raw(t: PtrInner<'_, $t>) -> PtrInner<'_, $u> { // SAFETY: We've asserted that their @@ -803,7 +808,7 @@ macro_rules! impl_size_eq { } } // SAFETY: See previous safety comment. - unsafe impl SizeEq<$u> for $t { + unsafe impl SizeFrom<$u> for $t { #[inline(always)] fn cast_from_raw(u: PtrInner<'_, $u>) -> PtrInner<'_, $t> { // SAFETY: See previous safety comment. @@ -815,17 +820,17 @@ macro_rules! impl_size_eq { } /// Invokes `$blk` in a context in which `$src<$t>` and `$dst<$u>` implement -/// `SizeEq`. +/// `SizeFrom`. /// -/// This macro emits code which implements `SizeEq`, and ensures that the impl -/// is sound via PME. +/// This macro emits code which implements `SizeComapt`, and ensures that the +/// impl is sound via PME. /// /// # Safety /// /// Inside of `$blk`, the caller must only use `$src` and `$dst` as `$src<$t>` /// and `$dst<$u>`. The caller must not use `$src` or `$dst` to wrap any other /// types. -macro_rules! unsafe_with_size_eq { +macro_rules! unsafe_with_size_from { (<$src:ident<$t:ident>, $dst:ident<$u:ident>> $blk:expr) => {{ crate::util::macros::__unsafe(); @@ -860,14 +865,14 @@ macro_rules! unsafe_with_size_eq { // We manually instantiate `cast_from_raw` below to ensure that this PME // can be triggered, and the caller promises not to use `$src` and // `$dst` with any wrapped types other than `$t` and `$u` respectively. - unsafe impl SizeEq<$src> for $dst + unsafe impl SizeFrom<$src> for $dst where T: KnownLayout, U: KnownLayout, { fn cast_from_raw(src: PtrInner<'_, $src>) -> PtrInner<'_, Self> { // SAFETY: `crate::layout::cast_from_raw` promises to satisfy - // the safety invariants of `SizeEq::cast_from_raw`, or to + // the safety invariants of `SizeFrom::cast_from_raw`, or to // generate a PME. Since `$src` and `$dst` are // `#[repr(transparent)]` wrappers around `T` and `U` // respectively, a `cast_from_raw` impl which satisfies the @@ -888,14 +893,12 @@ macro_rules! unsafe_with_size_eq { // See safety comment on the preceding `unsafe impl` block for an // explanation of why we need this block. if 1 == 0 { - let ptr = <$t as KnownLayout>::raw_dangling(); - #[allow(unused_unsafe)] - // SAFETY: This call is never executed. - let ptr = unsafe { crate::pointer::PtrInner::new(ptr) }; - #[allow(unused_unsafe)] - // SAFETY: This call is never executed. - let ptr = unsafe { cast!(ptr) }; - let _ = <$dst<$u> as SizeEq<$src<$t>>>::cast_from_raw(ptr); + use crate::pointer::PtrInner; + + #[allow(invalid_value, unused_unsafe)] + // SAFETY: This code is never executed. + let ptr: PtrInner<'_, $src<$t>> = unsafe { core::mem::MaybeUninit::uninit().assume_init() }; + let _ = <$dst<$u> as SizeFrom<$src<$t>>>::cast_from_raw(ptr); } impl_for_transmute_from!(T: ?Sized + TryFromBytes => TryFromBytes for $src[]); diff --git a/src/wrappers.rs b/src/wrappers.rs index 6d7891354a..9d3a7457be 100644 --- a/src/wrappers.rs +++ b/src/wrappers.rs @@ -200,7 +200,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).transmute::<_, _, (_, (_, _))>(); + let inner = Ptr::from_mut(self).transmute::<_, _, BecauseBidirectional>(); match inner.try_into_aligned() { Ok(aligned) => Ok(aligned.as_mut()), Err(err) => Err(err.map_src(|src| src.into_unalign().as_mut())), @@ -396,7 +396,10 @@ impl Deref for Unalign { impl DerefMut for Unalign { #[inline(always)] fn deref_mut(&mut self) -> &mut T { - Ptr::from_mut(self).transmute::<_, _, (_, (_, _))>().bikeshed_recall_aligned().as_mut() + Ptr::from_mut(self) + .transmute::<_, _, BecauseBidirectional>() + .bikeshed_recall_aligned() + .as_mut() } } diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index cc3a30c17a..9e02d5ae20 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -264,7 +264,7 @@ pub(crate) fn derive_is_bit_valid( let variant = unsafe { variants.cast_unsized_unchecked( |p: #zerocopy_crate::pointer::PtrInner<'_, ___ZerocopyVariants #ty_generics>| { - p.as_non_null().cast::<#variant_struct_ident #ty_generics>() + p.cast_sized::<#variant_struct_ident #ty_generics>() } ) }; @@ -325,14 +325,14 @@ pub(crate) fn derive_is_bit_valid( // primitive integer. let tag_ptr = unsafe { candidate.reborrow().cast_unsized_unchecked(|p: #zerocopy_crate::pointer::PtrInner<'_, Self>| { - p.as_non_null().cast::<___ZerocopyTagPrimitive>() + p.cast_sized::<___ZerocopyTagPrimitive>() }) }; // SAFETY: `tag_ptr` is casted from `candidate`, whose referent // is `Initialized`. Since we have not written uninitialized // bytes into the referent, `tag_ptr` is also `Initialized`. let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.recall_validity::<_, (_, (_, _))>().read_unaligned::<#zerocopy_crate::BecauseImmutable>() + tag_ptr.recall_validity().read_unaligned::<#zerocopy_crate::BecauseImmutable>() }; // SAFETY: @@ -347,7 +347,7 @@ pub(crate) fn derive_is_bit_valid( // `UnsafeCell`s. let raw_enum = unsafe { candidate.cast_unsized_unchecked(|p: #zerocopy_crate::pointer::PtrInner<'_, Self>| { - p.as_non_null().cast::<___ZerocopyRawEnum #ty_generics>() + p.cast_sized::<___ZerocopyRawEnum #ty_generics>() }) }; // SAFETY: `cast_unsized_unchecked` removes the initialization @@ -364,13 +364,15 @@ pub(crate) fn derive_is_bit_valid( // subfield pointer just points to a smaller portion of the // overall struct. let variants = unsafe { - raw_enum.cast_unsized_unchecked( |p: #zerocopy_crate::pointer::PtrInner<'_, ___ZerocopyRawEnum #ty_generics>| { + use #zerocopy_crate::pointer::PtrInner; + raw_enum.cast_unsized_unchecked( |p: PtrInner<'_, ___ZerocopyRawEnum #ty_generics>| { let p = p.as_non_null().as_ptr(); let ptr = core_reexport::ptr::addr_of_mut!((*p).variants); // SAFETY: `ptr` is a projection into `p`, which is // `NonNull`, and guaranteed not to wrap around the address // space. Thus, `ptr` cannot be null. - unsafe { core_reexport::ptr::NonNull::new_unchecked(ptr) } + let ptr = unsafe { core_reexport::ptr::NonNull::new_unchecked(ptr) }; + unsafe { PtrInner::new(ptr) } }) }; diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index c32af9135f..15fd7ec84f 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -758,6 +758,7 @@ fn derive_try_from_bytes_struct( ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference, { use #zerocopy_crate::util::macro_util::core_reexport; + use #zerocopy_crate::pointer::PtrInner; true #(&& { // SAFETY: @@ -768,7 +769,7 @@ 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: #zerocopy_crate::pointer::PtrInner<'_, Self>| { + let project = |slf: PtrInner<'_, Self>| { let slf = slf.as_non_null().as_ptr(); let field = core_reexport::ptr::addr_of_mut!((*slf).#field_names); // SAFETY: `cast_unsized_unchecked` promises that @@ -778,7 +779,9 @@ fn derive_try_from_bytes_struct( // object. In either case, this guarantees that // field projection will not wrap around the address // space, and so `field` will be non-null. - unsafe { core_reexport::ptr::NonNull::new_unchecked(field) } + let ptr = unsafe { core_reexport::ptr::NonNull::new_unchecked(field) }; + // TODO: Safety comment + unsafe { PtrInner::new(ptr) } }; candidate.reborrow().cast_unsized_unchecked(project) @@ -829,6 +832,7 @@ fn derive_try_from_bytes_union( ___ZerocopyAliasing: #zerocopy_crate::pointer::invariant::Reference, { use #zerocopy_crate::util::macro_util::core_reexport; + use #zerocopy_crate::pointer::PtrInner; false #(|| { // SAFETY: @@ -839,7 +843,7 @@ 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: #zerocopy_crate::pointer::PtrInner<'_, Self>| { + let project = |slf: PtrInner<'_, Self>| { let slf = slf.as_non_null().as_ptr(); let field = core_reexport::ptr::addr_of_mut!((*slf).#field_names); // SAFETY: `cast_unsized_unchecked` promises that @@ -849,7 +853,9 @@ fn derive_try_from_bytes_union( // object. In either case, this guarantees that // field projection will not wrap around the address // space, and so `field` will be non-null. - unsafe { core_reexport::ptr::NonNull::new_unchecked(field) } + let ptr = unsafe { core_reexport::ptr::NonNull::new_unchecked(field) }; + // TODO: Safety comment + unsafe { PtrInner::new(ptr) } }; candidate.reborrow().cast_unsized_unchecked(project) diff --git a/zerocopy-derive/src/output_tests.rs b/zerocopy-derive/src/output_tests.rs index acb9f90f86..20f8844762 100644 --- a/zerocopy-derive/src/output_tests.rs +++ b/zerocopy-derive/src/output_tests.rs @@ -782,7 +782,7 @@ fn test_try_from_bytes_enum() { candidate.reborrow().cast_unsized_unchecked(|p: ::zerocopy::pointer::PtrInner<'_, Self>| { p.as_non_null().cast::<___ZerocopyTagPrimitive>() }) }; let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.recall_validity::<_, (_, (_, _))>().read_unaligned::<::zerocopy::BecauseImmutable>() + tag_ptr.recall_validity().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { candidate.cast_unsized_unchecked(|p: ::zerocopy::pointer::PtrInner<'_, Self>| { p.as_non_null().cast::<___ZerocopyRawEnum<'a, N, X, Y>>() }) @@ -1106,7 +1106,7 @@ fn test_try_from_bytes_enum() { candidate.reborrow().cast_unsized_unchecked(|p: ::zerocopy::pointer::PtrInner<'_, Self>| { p.as_non_null().cast::<___ZerocopyTagPrimitive> ()}) }; let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.recall_validity::<_, (_, (_, _))>().read_unaligned::<::zerocopy::BecauseImmutable>() + tag_ptr.recall_validity().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { candidate.cast_unsized_unchecked(|p: ::zerocopy::pointer::PtrInner<'_, Self>| { p.as_non_null().cast::<___ZerocopyRawEnum<'a, N, X, Y>> ()}) @@ -1430,7 +1430,7 @@ fn test_try_from_bytes_enum() { candidate.reborrow().cast_unsized_unchecked(|p: ::zerocopy::pointer::PtrInner<'_, Self>| { p.as_non_null().cast::<___ZerocopyTagPrimitive> ()}) }; let tag_ptr = unsafe { tag_ptr.assume_initialized() }; - tag_ptr.recall_validity::<_, (_, (_, _))>().read_unaligned::<::zerocopy::BecauseImmutable>() + tag_ptr.recall_validity().read_unaligned::<::zerocopy::BecauseImmutable>() }; let raw_enum = unsafe { candidate.cast_unsized_unchecked(|p: ::zerocopy::pointer::PtrInner<'_, Self>| { p.as_non_null().cast::<___ZerocopyRawEnum<'a, N, X, Y>> ()})