diff --git a/src/impls.rs b/src/impls.rs index 0c84a115f1..53df018ae9 100644 --- a/src/impls.rs +++ b/src/impls.rs @@ -950,6 +950,7 @@ mod simd { #[cfg(test)] mod tests { use super::*; + use crate::pointer::invariant; #[test] fn test_impls() { diff --git a/src/lib.rs b/src/lib.rs index c939c1db6a..2db7816c0e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -360,7 +360,7 @@ use core::{ slice, }; -use crate::pointer::{invariant, BecauseExclusive}; +use crate::pointer::invariant::{self, BecauseExclusive}; #[cfg(any(feature = "alloc", test))] extern crate alloc; @@ -372,7 +372,7 @@ use core::alloc::Layout; // Used by `TryFromBytes::is_bit_valid`. #[doc(hidden)] -pub use crate::pointer::{BecauseImmutable, Maybe, MaybeAligned, Ptr}; +pub use crate::pointer::{invariant::BecauseImmutable, Maybe, MaybeAligned, Ptr}; // Used by `KnownLayout`. #[doc(hidden)] pub use crate::layout::*; diff --git a/src/pointer/invariant.rs b/src/pointer/invariant.rs index f85b1271a3..c48e0a196c 100644 --- a/src/pointer/invariant.rs +++ b/src/pointer/invariant.rs @@ -170,78 +170,41 @@ impl Validity for Initialized {} pub enum Valid {} impl Validity for Valid {} -pub mod aliasing_safety { - use super::*; - use crate::Immutable; - - /// Pointer conversions which do not violate aliasing. - /// - /// `U: AliasingSafe` implies that a pointer conversion from `T` to - /// `U` does not violate the aliasing invariant, `A`. This can be because - /// `A` is [`Exclusive`] or because neither `T` nor `U` permit interior - /// mutability. - /// - /// # Safety - /// - /// `U: AliasingSafe` if either of the following conditions holds: - /// - `A` is [`Exclusive`] - /// - `T` and `U` both implement [`Immutable`] - #[doc(hidden)] - pub unsafe trait AliasingSafe {} - - #[doc(hidden)] - pub trait AliasingSafeReason: sealed::Sealed {} - impl AliasingSafeReason for (R,) {} - - /// The conversion is safe because only one live `Ptr` or reference may exist to - /// the referent bytes at a time. - #[derive(Copy, Clone, Debug)] - #[doc(hidden)] - pub enum BecauseExclusive {} - impl AliasingSafeReason for BecauseExclusive {} - - /// The conversion is safe because no live `Ptr`s or references permit mutation. - #[derive(Copy, Clone, Debug)] - #[doc(hidden)] - pub enum BecauseImmutable {} - impl AliasingSafeReason for BecauseImmutable {} - - /// SAFETY: `T: AliasingSafe` because for all - /// `Ptr<'a, T, I>` such that `I::Aliasing = Exclusive`, there cannot exist - /// other live references to the memory referenced by `Ptr`. - unsafe impl AliasingSafe for U {} - - /// SAFETY: `U: AliasingSafe` because for all `Ptr<'a, T, - /// I>` and `Ptr<'a, U, I>` such that `I::Aliasing = A`, all live references and - /// live `Ptr`s agree, by invariant on `Immutable`, that the referenced bytes - /// contain no `UnsafeCell`s, and thus do not permit mutation except via - /// exclusive aliasing. - unsafe impl AliasingSafe for U - where - A: Aliasing, - T: Immutable, - U: Immutable, - { - } - - /// This ensures that `U: AliasingSafe` implies `T: AliasingSafe` in - /// a manner legible to rustc, which in turn means we can write simpler bounds in - /// some places. - /// - /// SAFETY: Per `U: AliasingSafe`, either: - /// - `A` is `Exclusive` - /// - `T` and `U` both implement `Immutable` - /// - /// Neither property depends on which of `T` and `U` are in the `Self` position - /// vs the first type parameter position. - unsafe impl AliasingSafe for T - where - A: Aliasing, - R: AliasingSafeReason, - U: AliasingSafe, - { - } -} +/// [`Ptr`](crate::Ptr) referents that permit unsynchronized read operations. +/// +/// `T: Read` implies that a pointer to `T` with aliasing `A` permits +/// unsynchronized read oeprations. This can be because `A` is [`Exclusive`] or +/// because `T` does not permit interior mutation. +/// +/// # Safety +/// +/// `T: Read` if either of the following conditions holds: +/// - `A` is [`Exclusive`] +/// - `T` implements [`Immutable`](crate::Immutable) +/// +/// As a consequence, if `T: Read`, then any `Ptr` is +/// permitted to perform unsynchronized reads from its referent. +pub trait Read {} + +impl Read for T {} +impl Read for T {} + +/// Used to disambiguate [`Read`] impls. +pub trait ReadReason: Sealed {} + +/// Unsynchronized reads are permitted because only one live [`Ptr`](crate::Ptr) +/// or reference may exist to the referent bytes at a time. +#[derive(Copy, Clone, Debug)] +#[doc(hidden)] +pub enum BecauseExclusive {} +impl ReadReason for BecauseExclusive {} + +/// Unsynchronized reads are permitted because no live [`Ptr`](crate::Ptr)s or +/// references permit interior mutation. +#[derive(Copy, Clone, Debug)] +#[doc(hidden)] +pub enum BecauseImmutable {} +impl ReadReason for BecauseImmutable {} use sealed::Sealed; mod sealed { @@ -262,7 +225,6 @@ mod sealed { impl Sealed for (A, AA, V) {} - impl Sealed for super::aliasing_safety::BecauseExclusive {} - impl Sealed for super::aliasing_safety::BecauseImmutable {} - impl Sealed for (S,) {} + impl Sealed for BecauseImmutable {} + impl Sealed for BecauseExclusive {} } diff --git a/src/pointer/mod.rs b/src/pointer/mod.rs index 9329f157c9..ceda0c6bd0 100644 --- a/src/pointer/mod.rs +++ b/src/pointer/mod.rs @@ -14,9 +14,7 @@ pub mod invariant; mod ptr; #[doc(hidden)] -pub use invariant::aliasing_safety::{ - AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable, -}; +pub use invariant::{BecauseExclusive, BecauseImmutable, Read, ReadReason}; #[doc(hidden)] pub use ptr::Ptr; @@ -50,11 +48,11 @@ where pub fn read_unaligned(self) -> T where T: Copy, - R: AliasingSafeReason, - T: AliasingSafe, + R: invariant::ReadReason, + T: invariant::Read, { // SAFETY: By invariant on `MaybeAligned`, `raw` contains - // validly-initialized data for `T`. By `T: AliasingSafe`, we are + // validly-initialized data for `T`. By `T: Read`, we are // permitted to perform a read of `self`'s referent. unsafe { self.as_inner().read_unaligned() } } diff --git a/src/pointer/ptr.rs b/src/pointer/ptr.rs index d828e284ea..78bf23d1b3 100644 --- a/src/pointer/ptr.rs +++ b/src/pointer/ptr.rs @@ -377,7 +377,7 @@ mod _conversions { // byte ranges. Since `p` and the returned pointer address the // same byte range, they refer to `UnsafeCell`s at the same byte // ranges. - let c = unsafe { self.cast_unsized(|p| T::cast_into_inner(p)) }; + let c = unsafe { self.cast_unsized_unchecked(|p| T::cast_into_inner(p)) }; // SAFETY: By invariant on `TransparentWrapper`, since `self` // satisfies the alignment invariant `I::Alignment`, `c` (of type // `T::Inner`) satisfies the given "applied" alignment invariant. @@ -411,7 +411,7 @@ mod _conversions { // `UnsafeCell`s at the same locations as `p`. let ptr = unsafe { #[allow(clippy::as_conversions)] - self.cast_unsized(|p: *mut T| p as *mut crate::Unalign) + self.cast_unsized_unchecked(|p: *mut T| p as *mut crate::Unalign) }; // SAFETY: `Unalign` promises to have the same bit validity as // `T`. @@ -651,13 +651,14 @@ 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, + T: TryFromBytes + Read, I::Aliasing: Reference, I: Invariants, + R: crate::pointer::ReadReason, { // 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 @@ -685,14 +686,19 @@ mod _transitions { /// Casts of the referent type. mod _casts { use super::*; - use crate::{pointer::invariant::aliasing_safety::*, CastError, SizeError}; + use crate::{CastError, SizeError}; impl<'a, T, I> Ptr<'a, T, I> where T: 'a + ?Sized, I: Invariants, { - /// Casts to a different (unsized) target type. + /// Casts to a different (unsized) target type without checking interior + /// mutability. + /// + /// Callers should prefer [`cast_unsized`] where possible. + /// + /// [`cast_unsized`]: Ptr::cast_unsized /// /// # Safety /// @@ -705,7 +711,7 @@ mod _casts { /// exist in `*p` #[doc(hidden)] #[inline] - pub unsafe fn cast_unsized *mut U>( + pub unsafe fn cast_unsized_unchecked *mut U>( self, cast: F, ) -> Ptr<'a, U, (I::Aliasing, Any, Any)> { @@ -767,6 +773,34 @@ mod _casts { // 8. `ptr`, trivially, conforms to the validity invariant of `Any`. unsafe { Ptr::new(ptr) } } + + /// Casts to a different (unsized) target type. + /// + /// # Safety + /// + /// 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` + #[doc(hidden)] + #[inline] + pub unsafe fn cast_unsized(self, cast: F) -> Ptr<'a, U, (I::Aliasing, Any, Any)> + where + T: Read, + U: 'a + ?Sized + Read, + R: ReadReason, + S: ReadReason, + F: FnOnce(*mut T) -> *mut U, + { + // 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 + // + // The caller promises all other safety preconditions. + unsafe { self.cast_unsized_unchecked(cast) } + } } impl<'a, T, I> Ptr<'a, T, I> @@ -778,8 +812,9 @@ mod _casts { #[allow(clippy::wrong_self_convention)] pub(crate) fn as_bytes(self) -> Ptr<'a, [u8], (I::Aliasing, Aligned, Valid)> where - [u8]: AliasingSafe, - R: AliasingSafeReason, + R: ReadReason, + T: Read, + I::Aliasing: Reference, { let bytes = match T::size_of_val_raw(self.as_inner().as_non_null()) { Some(bytes) => bytes, @@ -796,10 +831,6 @@ mod _casts { // pointer's address, and `bytes` is the length of `p`, so the // returned pointer addresses the same bytes as `p` // - `slice_from_raw_parts_mut` and `.cast` both preserve provenance - // - Because `[u8]: AliasingSafe`, either: - // - `I::Aliasing` is `Exclusive` - // - `T` and `[u8]` are both `Immutable`, in which case they - // trivially contain `UnsafeCell`s at identical locations let ptr: Ptr<'a, [u8], _> = unsafe { self.cast_unsized(|p: *mut T| { #[allow(clippy::as_conversions)] @@ -878,9 +909,9 @@ mod _casts { CastError, > where - R: AliasingSafeReason, + R: ReadReason, I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, + U: 'a + ?Sized + KnownLayout + Read, { let (inner, remainder) = self.as_inner().try_cast_into(cast_type, meta).map_err(|err| { @@ -893,12 +924,13 @@ mod _casts { })?; // SAFETY: - // 0. Since `U: AliasingSafe<[u8], I::Aliasing, _>`, either: + // 0. Since `U: Read`, either: // - `I::Aliasing` is `Exclusive`, in which case both `src` and // `ptr` conform to `Exclusive` - // - `I::Aliasing` is `Shared` or `Any` and both `U` and `[u8]` - // are `Immutable`. In this case, neither pointer permits - // mutation, and so `Shared` aliasing is satisfied. + // - `I::Aliasing` is `Shared` or `Any` and `U` is `Immutable` + // (we already know that `[u8]: Immutable`). In this case, + // neither `U` nor `[u8]` permit mutation, and so `Shared` + // aliasing is satisfied. // 1. `ptr` conforms to the alignment invariant of `Aligned` because // it is derived from `try_cast_into`, which promises that the // object described by `target` is validly aligned for `U`. @@ -939,8 +971,8 @@ mod _casts { ) -> Result, CastError> where I::Aliasing: Reference, - U: 'a + ?Sized + KnownLayout + AliasingSafe<[u8], I::Aliasing, R>, - R: AliasingSafeReason, + U: 'a + ?Sized + KnownLayout + Read, + R: ReadReason, { match self.try_cast_into(CastType::Prefix, meta) { Ok((slf, remainder)) => { @@ -984,11 +1016,8 @@ mod _casts { #[must_use] #[inline(always)] pub fn get_mut(self) -> Ptr<'a, T, I> { - // SAFETY: - // - The closure uses an `as` cast, which preserves address range - // and provenance. - // - We require `I: Invariants`, so we are not - // required to uphold `UnsafeCell` equality. + // SAFETY: The closure uses an `as` cast, which preserves address + // range and provenance. #[allow(clippy::as_conversions)] let ptr = unsafe { self.cast_unsized(|p| p as *mut T) }; @@ -1034,7 +1063,8 @@ mod _project { /// /// # Safety /// - /// `project` has the same safety preconditions as `cast_unsized`. + /// `project` has the same safety preconditions as + /// `cast_unsized_unchecked`. #[doc(hidden)] #[inline] pub unsafe fn project( @@ -1046,8 +1076,8 @@ mod _project { // `Initialized` pointer, we could remove this method entirely. // SAFETY: This method has the same safety preconditions as - // `cast_unsized`. - let ptr = unsafe { self.cast_unsized(projector) }; + // `cast_unsized_unchecked`. + let ptr = unsafe { self.cast_unsized_unchecked(projector) }; // SAFETY: If all of the bytes of `self` are initialized (as // promised by `I: Invariants`), then any diff --git a/src/util/macro_util.rs b/src/util/macro_util.rs index b94e82c573..1064a5b76b 100644 --- a/src/util/macro_util.rs +++ b/src/util/macro_util.rs @@ -25,10 +25,7 @@ use core::mem::{self, ManuallyDrop}; use core::ptr::{self, NonNull}; use crate::{ - pointer::{ - invariant::{self, Invariants}, - AliasingSafe, AliasingSafeReason, BecauseExclusive, BecauseImmutable, - }, + pointer::invariant::{self, BecauseExclusive, BecauseImmutable, Invariants, ReadReason}, Immutable, IntoBytes, Ptr, TryFromBytes, Unalign, ValidityError, }; @@ -527,11 +524,11 @@ fn try_cast_or_pme( ValidityError, Dst>, > where - Src: IntoBytes, - Dst: TryFromBytes + AliasingSafe, + Src: IntoBytes + invariant::Read, + Dst: TryFromBytes + invariant::Read, I: Invariants, I::Aliasing: invariant::Reference, - R: AliasingSafeReason, + R: ReadReason, { static_assert!(Src, Dst => mem::size_of::() == mem::size_of::()); @@ -540,10 +537,6 @@ 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 - // - Because `Dst: AliasingSafe`, either: - // - `I::Aliasing` is `Exclusive` - // - `Src` and `Dst` are both `Immutable`, in which case they - // trivially contain `UnsafeCell`s at identical locations #[allow(clippy::as_conversions)] let c_ptr = unsafe { src.cast_unsized(|p| p as *mut Dst) }; @@ -563,10 +556,6 @@ 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 - // - Because `Dst: AliasingSafe`, either: - // - `I::Aliasing` is `Exclusive` - // - `Src` and `Dst` are both `Immutable`, in which case they - // trivially contain `UnsafeCell`s at identical locations #[allow(clippy::as_conversions)] let ptr = unsafe { ptr.cast_unsized(|p| p as *mut Src) }; // SAFETY: `ptr` is `src`, and has the same alignment invariant. diff --git a/src/util/macros.rs b/src/util/macros.rs index 32fd7dd69a..3e6fbed8a1 100644 --- a/src/util/macros.rs +++ b/src/util/macros.rs @@ -151,7 +151,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::<$repr, _>(|p| p as *mut _) }; + let candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; // SAFETY: The caller has promised that the referenced memory region // will contain a valid `$repr`. @@ -175,7 +175,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::<$repr, _>(|p| p as *mut _) }; + let $candidate = unsafe { candidate.cast_unsized_unchecked::<$repr, _>(|p| p as *mut _) }; // Restore the invariant that the referent bytes are initialized. // SAFETY: The above cast does not uninitialize any referent bytes; diff --git a/zerocopy-derive/src/enum.rs b/zerocopy-derive/src/enum.rs index 7836117231..2bc9e033a7 100644 --- a/zerocopy-derive/src/enum.rs +++ b/zerocopy-derive/src/enum.rs @@ -259,15 +259,15 @@ pub(crate) fn derive_is_bit_valid( // `UnsafeCell`s will have the same location as in the // original type. let variant = unsafe { - variants.cast_unsized( + variants.cast_unsized_unchecked( |p: *mut ___ZerocopyVariants #ty_generics| { p as *mut #variant_struct_ident #ty_generics } ) }; - // SAFETY: `cast_unsized` removes the initialization - // invariant from `p`, so we re-assert that all of the bytes - // are initialized. + // SAFETY: `cast_unsized_unchecked` removes the + // initialization invariant from `p`, so we re-assert that + // all of the bytes are initialized. let variant = unsafe { variant.assume_initialized() }; < #variant_struct_ident #ty_generics as #trait_path @@ -321,7 +321,7 @@ pub(crate) fn derive_is_bit_valid( // - There are no `UnsafeCell`s in the tag because it is a // primitive integer. let tag_ptr = unsafe { - candidate.reborrow().cast_unsized(|p: *mut Self| { + candidate.reborrow().cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyTagPrimitive }) }; @@ -343,12 +343,13 @@ pub(crate) fn derive_is_bit_valid( // original enum, and so preserves the locations of any // `UnsafeCell`s. let raw_enum = unsafe { - candidate.cast_unsized(|p: *mut Self| { + candidate.cast_unsized_unchecked(|p: *mut Self| { p as *mut ___ZerocopyRawEnum #ty_generics }) }; - // SAFETY: `cast_unsized` removes the initialization invariant from - // `p`, so we re-assert that all of the bytes are initialized. + // SAFETY: `cast_unsized_unchecked` removes the initialization + // invariant from `p`, so we re-assert that all of the bytes are + // initialized. let raw_enum = unsafe { raw_enum.assume_initialized() }; // SAFETY: // - This projection returns a subfield of `this` using diff --git a/zerocopy-derive/src/lib.rs b/zerocopy-derive/src/lib.rs index 45c2de5d67..5d2f3ef43f 100644 --- a/zerocopy-derive/src/lib.rs +++ b/zerocopy-derive/src/lib.rs @@ -476,7 +476,7 @@ fn derive_try_from_bytes_union( // is guaranteed to be no more strict than this definition. See #696 // for a more in-depth discussion. fn is_bit_valid<___ZerocopyAliasing>( - mut candidate: ::zerocopy::Maybe<'_, Self, ___ZerocopyAliasing> + mut candidate: ::zerocopy::Maybe<'_, Self,___ZerocopyAliasing> ) -> ::zerocopy::util::macro_util::core_reexport::primitive::bool where ___ZerocopyAliasing: ::zerocopy::pointer::invariant::Reference, diff --git a/zerocopy-derive/tests/include.rs b/zerocopy-derive/tests/include.rs index 7a4bf32890..964ff17fb9 100644 --- a/zerocopy-derive/tests/include.rs +++ b/zerocopy-derive/tests/include.rs @@ -119,7 +119,7 @@ pub mod util { let ptr = super::imp::Ptr::from_ref(&buf); // SAFETY: `T` and `MaybeUninit` have the same layout, so this is a // size-preserving cast. It is also a provenance-preserving cast. - let ptr = unsafe { ptr.cast_unsized(|p| p as *mut T) }; + let ptr = unsafe { ptr.cast_unsized_unchecked(|p| p as *mut T) }; // SAFETY: This is intentionally unsound; see the preceding comment. let ptr = unsafe { ptr.assume_initialized() }; assert!(::is_bit_valid(ptr)); diff --git a/zerocopy-derive/tests/struct_try_from_bytes.rs b/zerocopy-derive/tests/struct_try_from_bytes.rs index 5aa9d70695..8a4c70536c 100644 --- a/zerocopy-derive/tests/struct_try_from_bytes.rs +++ b/zerocopy-derive/tests/struct_try_from_bytes.rs @@ -78,7 +78,7 @@ fn two_bad() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut Two) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Two) }; // SAFETY: `candidate`'s referent is as-initialized as `Two`. let candidate = unsafe { candidate.assume_initialized() }; @@ -108,7 +108,7 @@ fn un_sized() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut Unsized) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Unsized) }; // SAFETY: `candidate`'s referent is as-initialized as `Two`. let candidate = unsafe { candidate.assume_initialized() }; @@ -163,7 +163,7 @@ fn test_maybe_from_bytes() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut MaybeFromBytes) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut MaybeFromBytes) }; // SAFETY: `[u8]` consists entirely of initialized bytes. let candidate = unsafe { candidate.assume_initialized() }; diff --git a/zerocopy-derive/tests/union_try_from_bytes.rs b/zerocopy-derive/tests/union_try_from_bytes.rs index 8c3183e5d8..f2bd84ee4e 100644 --- a/zerocopy-derive/tests/union_try_from_bytes.rs +++ b/zerocopy-derive/tests/union_try_from_bytes.rs @@ -73,7 +73,7 @@ fn two_bad() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut Two) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut Two) }; // SAFETY: `candidate`'s referent is as-initialized as `Two`. let candidate = unsafe { candidate.assume_initialized() }; @@ -102,7 +102,7 @@ fn bool_and_zst() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut BoolAndZst) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut BoolAndZst) }; // SAFETY: `candidate`'s referent is fully initialized. let candidate = unsafe { candidate.assume_initialized() }; @@ -130,7 +130,7 @@ fn test_maybe_from_bytes() { // the same bytes as `c`. // - The cast preserves provenance. // - Neither the input nor output types contain any `UnsafeCell`s. - let candidate = unsafe { candidate.cast_unsized(|p| p as *mut MaybeFromBytes) }; + let candidate = unsafe { candidate.cast_unsized_unchecked(|p| p as *mut MaybeFromBytes) }; // SAFETY: `[u8]` consists entirely of initialized bytes. let candidate = unsafe { candidate.assume_initialized() };