@@ -354,7 +354,7 @@ use core::{
354
354
fmt:: { self , Debug , Display , Formatter } ,
355
355
hash:: Hasher ,
356
356
marker:: PhantomData ,
357
- mem:: { self , ManuallyDrop , MaybeUninit } ,
357
+ mem:: { self , ManuallyDrop , MaybeUninit as CoreMaybeUninit } ,
358
358
num:: {
359
359
NonZeroI128 , NonZeroI16 , NonZeroI32 , NonZeroI64 , NonZeroI8 , NonZeroIsize , NonZeroU128 ,
360
360
NonZeroU16 , NonZeroU32 , NonZeroU64 , NonZeroU8 , NonZeroUsize , Wrapping ,
@@ -732,6 +732,15 @@ pub unsafe trait KnownLayout {
732
732
/// This is `()` for sized types and `usize` for slice DSTs.
733
733
type PointerMetadata : PointerMetadata ;
734
734
735
+ /// A maybe-uninitialized analog of `Self`
736
+ ///
737
+ /// # Safety
738
+ ///
739
+ /// `Self::LAYOUT` and `Self::MaybeUninit::LAYOUT` are identical.
740
+ /// `Self::MaybeUninit` admits uninitialized bytes in all positions.
741
+ #[ doc( hidden) ]
742
+ type MaybeUninit : ?Sized + KnownLayout < PointerMetadata = Self :: PointerMetadata > ;
743
+
735
744
/// The layout of `Self`.
736
745
///
737
746
/// # Safety
@@ -864,6 +873,35 @@ unsafe impl<T> KnownLayout for [T] {
864
873
865
874
type PointerMetadata = usize ;
866
875
876
+ // SAFETY: `CoreMaybeUninit<T>::LAYOUT` and `T::LAYOUT` are identical
877
+ // because `CoreMaybeUninit<T>` has the same size and alignment as `T` [1].
878
+ // Consequently, `[CoreMaybeUninit<T>]::LAYOUT` and `[T]::LAYOUT` are
879
+ // identical, because they both lack a fixed-sized prefix and because they
880
+ // inherit the alignments of their inner element type (which are identical)
881
+ // [2][3].
882
+ //
883
+ // `[CoreMaybeUninit<T>]` admits uninitialized bytes at all positions
884
+ // because `CoreMaybeUninit<T>` admits uninitialized bytes at all positions
885
+ // and because the inner elements of `[CoreMaybeUninit<T>]` are laid out
886
+ // back-to-back [2][3].
887
+ //
888
+ // [1] Per https://doc.rust-lang.org/1.81.0/std/mem/union.MaybeUninit.html#layout-1:
889
+ //
890
+ // `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as
891
+ // `T`
892
+ //
893
+ // [2] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#slice-layout:
894
+ //
895
+ // Slices have the same layout as the section of the array they slice.
896
+ //
897
+ // [3] Per https://doc.rust-lang.org/1.82.0/reference/type-layout.html#array-layout:
898
+ //
899
+ // An array of `[T; N]` has a size of `size_of::<T>() * N` and the same
900
+ // alignment of `T`. Arrays are laid out so that the zero-based `nth`
901
+ // element of the array is offset from the start of the array by `n *
902
+ // size_of::<T>()` bytes.
903
+ type MaybeUninit = [ CoreMaybeUninit < T > ] ;
904
+
867
905
const LAYOUT : DstLayout = DstLayout :: for_slice :: < T > ( ) ;
868
906
869
907
// SAFETY: `.cast` preserves address and provenance. The returned pointer
@@ -916,9 +954,11 @@ impl_known_layout!(
916
954
T => Option <T >,
917
955
T : ?Sized => PhantomData <T >,
918
956
T => Wrapping <T >,
919
- T => MaybeUninit <T >,
957
+ T => CoreMaybeUninit <T >,
920
958
T : ?Sized => * const T ,
921
- T : ?Sized => * mut T
959
+ T : ?Sized => * mut T ,
960
+ T : ?Sized => & ' _ T ,
961
+ T : ?Sized => & ' _ mut T ,
922
962
) ;
923
963
impl_known_layout ! ( const N : usize , T => [ T ; N ] ) ;
924
964
@@ -949,6 +989,21 @@ safety_comment! {
949
989
unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T ) ] UnsafeCell <T >) ;
950
990
}
951
991
992
+ safety_comment ! {
993
+ /// SAFETY:
994
+ /// - By consequence of the invariant on `T::MaybeUninit` that `T::LAYOUT`
995
+ /// and `T::MaybeUninit::LAYOUT` are equal, `T` and `T::MaybeUninit`
996
+ /// have the same:
997
+ /// - Fixed prefix size
998
+ /// - Alignment
999
+ /// - (For DSTs) trailing slice element size
1000
+ /// - By consequence of the above, referents `T::MaybeUninit` and `T` have
1001
+ /// the require the same kind of pointer metadata, and thus it is valid to
1002
+ /// perform an `as` cast from `*mut T` and `*mut T::MaybeUninit`, and this
1003
+ /// operation preserves referent size (ie, `size_of_val_raw`).
1004
+ unsafe_impl_known_layout!( T : ?Sized + KnownLayout => #[ repr( T :: MaybeUninit ) ] MaybeUninit <T >) ;
1005
+ }
1006
+
952
1007
/// Analyzes whether a type is [`FromZeros`].
953
1008
///
954
1009
/// This derive analyzes, at compile time, whether the annotated type satisfies
@@ -2550,7 +2605,7 @@ pub unsafe trait TryFromBytes {
2550
2605
where
2551
2606
Self : Sized ,
2552
2607
{
2553
- let candidate = match MaybeUninit :: < Self > :: read_from_bytes ( source) {
2608
+ let candidate = match CoreMaybeUninit :: < Self > :: read_from_bytes ( source) {
2554
2609
Ok ( candidate) => candidate,
2555
2610
Err ( e) => {
2556
2611
return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2611,7 +2666,7 @@ pub unsafe trait TryFromBytes {
2611
2666
where
2612
2667
Self : Sized ,
2613
2668
{
2614
- let ( candidate, suffix) = match MaybeUninit :: < Self > :: read_from_prefix ( source) {
2669
+ let ( candidate, suffix) = match CoreMaybeUninit :: < Self > :: read_from_prefix ( source) {
2615
2670
Ok ( candidate) => candidate,
2616
2671
Err ( e) => {
2617
2672
return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2673,7 +2728,7 @@ pub unsafe trait TryFromBytes {
2673
2728
where
2674
2729
Self : Sized ,
2675
2730
{
2676
- let ( prefix, candidate) = match MaybeUninit :: < Self > :: read_from_suffix ( source) {
2731
+ let ( prefix, candidate) = match CoreMaybeUninit :: < Self > :: read_from_suffix ( source) {
2677
2732
Ok ( candidate) => candidate,
2678
2733
Err ( e) => {
2679
2734
return Err ( TryReadError :: Size ( e. with_dst ( ) ) ) ;
@@ -2746,7 +2801,7 @@ fn swap<T, U>((t, u): (T, U)) -> (U, T) {
2746
2801
#[ inline( always) ]
2747
2802
unsafe fn try_read_from < S , T : TryFromBytes > (
2748
2803
source : S ,
2749
- mut candidate : MaybeUninit < T > ,
2804
+ mut candidate : CoreMaybeUninit < T > ,
2750
2805
) -> Result < T , TryReadError < S , T > > {
2751
2806
// We use `from_mut` despite not mutating via `c_ptr` so that we don't need
2752
2807
// to add a `T: Immutable` bound.
@@ -3035,72 +3090,11 @@ pub unsafe trait FromZeros: TryFromBytes {
3035
3090
where
3036
3091
Self : KnownLayout < PointerMetadata = usize > ,
3037
3092
{
3038
- let size = match count. size_for_metadata ( Self :: LAYOUT ) {
3039
- Some ( size) => size,
3040
- None => return Err ( AllocError ) ,
3041
- } ;
3042
-
3043
- let align = Self :: LAYOUT . align . get ( ) ;
3044
- // On stable Rust versions <= 1.64.0, `Layout::from_size_align` has a
3045
- // bug in which sufficiently-large allocations (those which, when
3046
- // rounded up to the alignment, overflow `isize`) are not rejected,
3047
- // which can cause undefined behavior. See #64 for details.
3048
- //
3049
- // TODO(#67): Once our MSRV is > 1.64.0, remove this assertion.
3050
- #[ allow( clippy:: as_conversions) ]
3051
- let max_alloc = ( isize:: MAX as usize ) . saturating_sub ( align) ;
3052
- if size > max_alloc {
3053
- return Err ( AllocError ) ;
3054
- }
3055
-
3056
- // TODO(https://github.com/rust-lang/rust/issues/55724): Use
3057
- // `Layout::repeat` once it's stabilized.
3058
- let layout = Layout :: from_size_align ( size, align) . or ( Err ( AllocError ) ) ?;
3059
-
3060
- let ptr = if layout. size ( ) != 0 {
3061
- // TODO(#429): Add a "SAFETY" comment and remove this `allow`.
3062
- #[ allow( clippy:: undocumented_unsafe_blocks) ]
3063
- let ptr = unsafe { alloc:: alloc:: alloc_zeroed ( layout) } ;
3064
- match NonNull :: new ( ptr) {
3065
- Some ( ptr) => ptr,
3066
- None => return Err ( AllocError ) ,
3067
- }
3068
- } else {
3069
- let align = Self :: LAYOUT . align . get ( ) ;
3070
- // We use `transmute` instead of an `as` cast since Miri (with
3071
- // strict provenance enabled) notices and complains that an `as`
3072
- // cast creates a pointer with no provenance. Miri isn't smart
3073
- // enough to realize that we're only executing this branch when
3074
- // we're constructing a zero-sized `Box`, which doesn't require
3075
- // provenance.
3076
- //
3077
- // SAFETY: any initialized bit sequence is a bit-valid `*mut u8`.
3078
- // All bits of a `usize` are initialized.
3079
- #[ allow( clippy:: useless_transmute) ]
3080
- let dangling = unsafe { mem:: transmute :: < usize , * mut u8 > ( align) } ;
3081
- // SAFETY: `dangling` is constructed from `Self::LAYOUT.align`,
3082
- // which is a `NonZeroUsize`, which is guaranteed to be non-zero.
3083
- //
3084
- // `Box<[T]>` does not allocate when `T` is zero-sized or when `len`
3085
- // is zero, but it does require a non-null dangling pointer for its
3086
- // allocation.
3087
- //
3088
- // TODO(https://github.com/rust-lang/rust/issues/95228): Use
3089
- // `std::ptr::without_provenance` once it's stable. That may
3090
- // optimize better. As written, Rust may assume that this consumes
3091
- // "exposed" provenance, and thus Rust may have to assume that this
3092
- // may consume provenance from any pointer whose provenance has been
3093
- // exposed.
3094
- unsafe { NonNull :: new_unchecked ( dangling) }
3095
- } ;
3096
-
3097
- let ptr = Self :: raw_from_ptr_len ( ptr, count) ;
3098
-
3099
- // TODO(#429): Add a "SAFETY" comment and remove this `allow`. Make sure
3100
- // to include a justification that `ptr.as_ptr()` is validly-aligned in
3101
- // the ZST case (in which we manually construct a dangling pointer).
3102
- #[ allow( clippy:: undocumented_unsafe_blocks) ]
3103
- Ok ( unsafe { Box :: from_raw ( ptr. as_ptr ( ) ) } )
3093
+ // SAFETY: `alloc::alloc::alloc_zeroed` is a valid argument of
3094
+ // `new_box`. The referent of the pointer returned by `alloc_zeroed`
3095
+ // (and, consequently, the `Box` derived from it) is a valid instance of
3096
+ // `Self`, because `Self` is `FromZeros`.
3097
+ unsafe { crate :: util:: new_box ( count, alloc:: alloc:: alloc_zeroed) }
3104
3098
}
3105
3099
3106
3100
#[ deprecated( since = "0.8.0" , note = "renamed to `FromZeros::new_box_zeroed_with_elems`" ) ]
@@ -4562,7 +4556,7 @@ pub unsafe trait FromBytes: FromZeros {
4562
4556
Self : Sized ,
4563
4557
R : io:: Read ,
4564
4558
{
4565
- let mut buf = MaybeUninit :: < Self > :: zeroed ( ) ;
4559
+ let mut buf = CoreMaybeUninit :: < Self > :: zeroed ( ) ;
4566
4560
let ptr = Ptr :: from_mut ( & mut buf) ;
4567
4561
// SAFETY: `buf` consists entirely of initialized, zeroed bytes.
4568
4562
let ptr = unsafe { ptr. assume_validity :: < invariant:: Initialized > ( ) } ;
0 commit comments