@@ -8,7 +8,7 @@ use std::{
88} ; 
99
1010#[ cfg( feature = "randomize" ) ]  
11- use  rand:: { seq:: SliceRandom ,  SeedableRng } ; 
11+ use  rand:: { seq:: SliceRandom ,  Rng ,   SeedableRng } ; 
1212#[ cfg( feature = "randomize" ) ]  
1313use  rand_xoshiro:: Xoshiro128StarStar ; 
1414
@@ -61,18 +61,30 @@ pub trait LayoutCalculator {
6161        } 
6262    } 
6363
64-     fn  univariant < ' a ,  V :   Idx ,  F :   Deref < Target  =  & ' a   LayoutS < V > >  +  Debug > ( 
64+     fn  univariant < ' a ,  V ,  F ,   N > ( 
6565        & self , 
6666        dl :  & TargetDataLayout , 
6767        fields :  & [ F ] , 
6868        repr :  & ReprOptions , 
6969        kind :  StructKind , 
70-     )  -> Option < LayoutS < V > >  { 
70+         option_niche_guaranteed :  N , 
71+     )  -> Option < LayoutS < V > > 
72+     where 
73+         V :  Idx , 
74+         F :  Deref < Target  = & ' a  LayoutS < V > >  + Debug , 
75+         N :  Fn ( & Self )  -> bool  + Copy , 
76+     { 
7177        let  pack = repr. pack ; 
7278        let  mut  align = if  pack. is_some ( )  {  dl. i8_align  }  else  {  dl. aggregate_align  } ; 
7379        let  mut  inverse_memory_index:  Vec < u32 >  = ( 0 ..fields. len ( )  as  u32 ) . collect ( ) ; 
74-         let  optimize = !repr. inhibit_struct_field_reordering_opt ( ) ; 
75-         if  optimize { 
80+ 
81+         // `ReprOptions.layout_seed` is a deterministic seed that we can use to 
82+         // randomize field ordering with 
83+         #[ cfg( feature = "randomize" ) ]  
84+         let  mut  rng = Xoshiro128StarStar :: seed_from_u64 ( repr. field_shuffle_seed ) ; 
85+ 
86+         let  can_optimize = !repr. inhibit_struct_field_reordering_opt ( ) ; 
87+         if  can_optimize { 
7688            let  end =
7789                if  let  StructKind :: MaybeUnsized  = kind {  fields. len ( )  - 1  }  else  {  fields. len ( )  } ; 
7890            let  optimizing = & mut  inverse_memory_index[ ..end] ; 
@@ -94,16 +106,11 @@ pub trait LayoutCalculator {
94106            // the field ordering to try and catch some code making assumptions about layouts 
95107            // we don't guarantee 
96108            if  repr. can_randomize_type_layout ( )  && cfg ! ( feature = "randomize" )  { 
109+                 // Shuffle the ordering of the fields 
97110                #[ cfg( feature = "randomize" ) ]  
98-                 { 
99-                     // `ReprOptions.layout_seed` is a deterministic seed that we can use to 
100-                     // randomize field ordering with 
101-                     let  mut  rng = Xoshiro128StarStar :: seed_from_u64 ( repr. field_shuffle_seed ) ; 
111+                 optimizing. shuffle ( & mut  rng) ; 
102112
103-                     // Shuffle the ordering of the fields 
104-                     optimizing. shuffle ( & mut  rng) ; 
105-                 } 
106-                 // Otherwise we just leave things alone and actually optimize the type's fields 
113+             // Otherwise we just leave things alone and actually optimize the type's fields 
107114            }  else  { 
108115                match  kind { 
109116                    StructKind :: AlwaysSized  | StructKind :: MaybeUnsized  => { 
@@ -173,6 +180,32 @@ pub trait LayoutCalculator {
173180            offset = offset. align_to ( field_align. abi ) ; 
174181            align = align. max ( field_align) ; 
175182
183+             // If `-Z randomize-layout` is enabled, we pad each field by a multiple of its alignment 
184+             // If layout randomization is disabled, we don't pad it by anything and if it is 
185+             // we multiply the field's alignment by anything from zero to the user provided 
186+             // maximum multiple (defaults to three) 
187+             // 
188+             // When `-Z randomize-layout` is enabled that doesn't necessarily mean we can 
189+             // go ham on every type that at first glance looks valid for layout optimization. 
190+             // `Option` specifically has layout guarantees when it has specific `T` substitutions, 
191+             // such as `Option<NonNull<_>>` or `Option<NonZeroUsize>` both being exactly one `usize` 
192+             // large. As such, we have to ensure that the type doesn't guarantee niche optimization 
193+             // with the current payload 
194+             #[ cfg( feature = "randomize" ) ]  
195+             if  repr. can_randomize_type_layout ( )  && !option_niche_guaranteed ( self )  { 
196+                 let  align_bytes = field_align. abi . bytes ( ) ; 
197+                 let  random_padding = align_bytes
198+                     . checked_mul ( rng. gen_range ( 0 ..=repr. random_padding_max_factor  as  u64 ) ) 
199+                     . unwrap_or ( align_bytes) ; 
200+ 
201+                 // Attempt to add our extra padding, defaulting to the type's alignment 
202+                 if  let  Some ( randomized_offset)  =
203+                     offset. checked_add ( Size :: from_bytes ( random_padding) ,  dl) 
204+                 { 
205+                     offset = randomized_offset; 
206+                 } 
207+             } 
208+ 
176209            debug ! ( "univariant offset: {:?} field: {:#?}" ,  offset,  field) ; 
177210            offsets[ i as  usize ]  = offset; 
178211
@@ -199,7 +232,7 @@ pub trait LayoutCalculator {
199232        // Field 5 would be the first element, so memory_index is i: 
200233        // Note: if we didn't optimize, it's already right. 
201234        let  memory_index =
202-             if  optimize  {  invert_mapping ( & inverse_memory_index)  }  else  {  inverse_memory_index } ; 
235+             if  can_optimize  {  invert_mapping ( & inverse_memory_index)  }  else  {  inverse_memory_index } ; 
203236        let  size = min_size. align_to ( align. abi ) ; 
204237        let  mut  abi = Abi :: Aggregate  {  sized } ; 
205238        // Unpack newtype ABIs and find scalar pairs. 
@@ -216,7 +249,7 @@ pub trait LayoutCalculator {
216249                        match  field. abi  { 
217250                            // For plain scalars, or vectors of them, we can't unpack 
218251                            // newtypes for `#[repr(C)]`, as that affects C ABIs. 
219-                             Abi :: Scalar ( _)  | Abi :: Vector  {  .. }  if  optimize  => { 
252+                             Abi :: Scalar ( _)  | Abi :: Vector  {  .. }  if  can_optimize  => { 
220253                                abi = field. abi ; 
221254                            } 
222255                            // But scalar pairs are Rust-specific and get 
@@ -290,7 +323,7 @@ pub trait LayoutCalculator {
290323        } 
291324    } 
292325
293-     fn  layout_of_struct_or_enum < ' a ,  V :   Idx ,  F :   Deref < Target  =  & ' a   LayoutS < V > >  +  Debug > ( 
326+     fn  layout_of_struct_or_enum < ' a ,  V ,  F ,   N > ( 
294327        & self , 
295328        repr :  & ReprOptions , 
296329        variants :  & IndexVec < V ,  Vec < F > > , 
@@ -301,7 +334,13 @@ pub trait LayoutCalculator {
301334        discriminants :  impl  Iterator < Item  = ( V ,  i128 ) > , 
302335        niche_optimize_enum :  bool , 
303336        always_sized :  bool , 
304-     )  -> Option < LayoutS < V > >  { 
337+         option_niche_guaranteed :  N , 
338+     )  -> Option < LayoutS < V > > 
339+     where 
340+         V :  Idx , 
341+         F :  Deref < Target  = & ' a  LayoutS < V > >  + Debug , 
342+         N :  Fn ( & Self )  -> bool  + Copy , 
343+     { 
305344        let  dl = self . current_data_layout ( ) ; 
306345        let  dl = dl. borrow ( ) ; 
307346
@@ -354,7 +393,7 @@ pub trait LayoutCalculator {
354393                if  !always_sized {  StructKind :: MaybeUnsized  }  else  {  StructKind :: AlwaysSized  } 
355394            } ; 
356395
357-             let  mut  st = self . univariant ( dl,  & variants[ v] ,  repr,  kind) ?; 
396+             let  mut  st = self . univariant ( dl,  & variants[ v] ,  repr,  kind,  option_niche_guaranteed ) ?; 
358397            st. variants  = Variants :: Single  {  index :  v } ; 
359398
360399            if  is_unsafe_cell { 
@@ -457,7 +496,13 @@ pub trait LayoutCalculator {
457496            let  mut  variant_layouts = variants
458497                . iter_enumerated ( ) 
459498                . map ( |( j,  v) | { 
460-                     let  mut  st = self . univariant ( dl,  v,  repr,  StructKind :: AlwaysSized ) ?; 
499+                     let  mut  st = self . univariant ( 
500+                         dl, 
501+                         v, 
502+                         repr, 
503+                         StructKind :: AlwaysSized , 
504+                         option_niche_guaranteed, 
505+                     ) ?; 
461506                    st. variants  = Variants :: Single  {  index :  j } ; 
462507
463508                    align = align. max ( st. align ) ; 
@@ -650,6 +695,7 @@ pub trait LayoutCalculator {
650695                    field_layouts, 
651696                    repr, 
652697                    StructKind :: Prefixed ( min_ity. size ( ) ,  prefix_align) , 
698+                     option_niche_guaranteed, 
653699                ) ?; 
654700                st. variants  = Variants :: Single  {  index :  i } ; 
655701                // Find the first field we can't move later 
0 commit comments