diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2025-01-10 06:28:37 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-01-10 06:28:37 +0100 |
| commit | eaf420638e68e8acf800ae9e57457bba096d033a (patch) | |
| tree | 2effce7ee6a9610bc647b071118711e28c38d935 /compiler | |
| parent | 62bf38fa600f4beb878d61c537837729d4ee689e (diff) | |
| parent | d89b6d5ac6ceb7f735c8d2c7397fb6bb0e0e3020 (diff) | |
| download | rust-eaf420638e68e8acf800ae9e57457bba096d033a.tar.gz rust-eaf420638e68e8acf800ae9e57457bba096d033a.zip | |
Rollup merge of #133088 - the8472:randomize-me-harder, r=workingjubilee
`-Zrandomize-layout` harder. `Foo<T> != Foo<U>` Tracking issue: #106764 Previously randomize-layout only used a deterministic shuffle based on the seed stored in an Adt's ReprOptions, meaning that `Foo<T>` and `Foo<U>` were shuffled by the same seed. This change adds a similar seed to each calculated LayoutData so that a struct can be randomized both based on the layout of its fields and its per-type seed. Primitives start with simple seed derived from some of their properties. Though some types can no longer be distinguished at that point, e.g. usize and u64 will still be treated the same.
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_abi/src/layout.rs | 43 | ||||
| -rw-r--r-- | compiler/rustc_abi/src/lib.rs | 39 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/ty/layout.rs | 1 | ||||
| -rw-r--r-- | compiler/rustc_ty_utils/src/layout.rs | 10 |
4 files changed, 86 insertions, 7 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 226a46f605c..b8773f9ff38 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -119,6 +119,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { .chain(Niche::from_scalar(dl, Size::ZERO, a)) .max_by_key(|niche| niche.available(dl)); + let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes()); + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { @@ -131,6 +133,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { size, max_repr_align: None, unadjusted_abi_align: align.abi, + randomization_seed: combined_seed, } } @@ -223,6 +226,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align.abi, + randomization_seed: 0, } } @@ -385,6 +389,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { return Err(LayoutCalculatorError::EmptyUnion); }; + let combined_seed = only_variant + .iter() + .map(|v| v.randomization_seed) + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + Ok(LayoutData { variants: Variants::Single { index: only_variant_idx }, fields: FieldsShape::Union(union_field_count), @@ -394,6 +403,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { size: size.align_to(align.abi), max_repr_align, unadjusted_abi_align, + randomization_seed: combined_seed, }) } @@ -650,6 +660,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { BackendRepr::Memory { sized: true } }; + let combined_seed = variant_layouts + .iter() + .map(|v| v.randomization_seed) + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + let layout = LayoutData { variants: Variants::Multiple { tag: niche_scalar, @@ -671,6 +686,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { align, max_repr_align, unadjusted_abi_align, + randomization_seed: combined_seed, }; Some(TmpLayout { layout, variants: variant_layouts }) @@ -961,6 +977,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag); + let combined_seed = layout_variants + .iter() + .map(|v| v.randomization_seed) + .fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed)); + let tagged_layout = LayoutData { variants: Variants::Multiple { tag, @@ -978,6 +999,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { size, max_repr_align, unadjusted_abi_align, + randomization_seed: combined_seed, }; let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants }; @@ -1030,12 +1052,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { let mut max_repr_align = repr.align; let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect(); let optimize_field_order = !repr.inhibit_struct_field_reordering(); - if optimize_field_order && fields.len() > 1 { - let end = - if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; - let optimizing = &mut inverse_memory_index.raw[..end]; - let fields_excluding_tail = &fields.raw[..end]; + let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() }; + let optimizing = &mut inverse_memory_index.raw[..end]; + let fields_excluding_tail = &fields.raw[..end]; + // unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts. + let field_seed = fields_excluding_tail + .iter() + .fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed)); + if optimize_field_order && fields.len() > 1 { // If `-Z randomize-layout` was enabled for the type definition we can shuffle // the field ordering to try and catch some code making assumptions about layouts // we don't guarantee. @@ -1046,8 +1071,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { use rand::seq::SliceRandom; // `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field // ordering. - let mut rng = - rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed); + let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64( + field_seed.wrapping_add(repr.field_shuffle_seed), + ); // Shuffle the ordering of the fields. optimizing.shuffle(&mut rng); @@ -1344,6 +1370,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { unadjusted_abi_align }; + let seed = field_seed.wrapping_add(repr.field_shuffle_seed); + Ok(LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Arbitrary { offsets, memory_index }, @@ -1353,6 +1381,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> { size, max_repr_align, unadjusted_abi_align, + randomization_seed: seed, }) } diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 7fa869a509c..8ad33749f34 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -1719,6 +1719,18 @@ pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> { /// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment /// in some cases. pub unadjusted_abi_align: Align, + + /// The randomization seed based on this type's own repr and its fields. + /// + /// Since randomization is toggled on a per-crate basis even crates that do not have randomization + /// enabled should still calculate a seed so that downstream uses can use it to distinguish different + /// types. + /// + /// For every T and U for which we do not guarantee that a repr(Rust) `Foo<T>` can be coerced or + /// transmuted to `Foo<U>` we aim to create probalistically distinct seeds so that Foo can choose + /// to reorder its fields based on that information. The current implementation is a conservative + /// approximation of this goal. + pub randomization_seed: u64, } impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { @@ -1739,6 +1751,30 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar); let size = scalar.size(cx); let align = scalar.align(cx); + + let range = scalar.valid_range(cx); + + // All primitive types for which we don't have subtype coercions should get a distinct seed, + // so that types wrapping them can use randomization to arrive at distinct layouts. + // + // Some type information is already lost at this point, so as an approximation we derive + // the seed from what remains. For example on 64-bit targets usize and u64 can no longer + // be distinguished. + let randomization_seed = size + .bytes() + .wrapping_add( + match scalar.primitive() { + Primitive::Int(_, true) => 1, + Primitive::Int(_, false) => 2, + Primitive::Float(_) => 3, + Primitive::Pointer(_) => 4, + } << 32, + ) + // distinguishes references from pointers + .wrapping_add((range.start as u64).rotate_right(16)) + // distinguishes char from u32 and bool from u8 + .wrapping_add((range.end as u64).rotate_right(16)); + LayoutData { variants: Variants::Single { index: VariantIdx::new(0) }, fields: FieldsShape::Primitive, @@ -1748,6 +1784,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> { align, max_repr_align: None, unadjusted_abi_align: align.abi, + randomization_seed, } } } @@ -1770,6 +1807,7 @@ where variants, max_repr_align, unadjusted_abi_align, + ref randomization_seed, } = self; f.debug_struct("Layout") .field("size", size) @@ -1780,6 +1818,7 @@ where .field("variants", variants) .field("max_repr_align", max_repr_align) .field("unadjusted_abi_align", unadjusted_abi_align) + .field("randomization_seed", randomization_seed) .finish() } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 6e6da6de749..8d4d127607d 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -770,6 +770,7 @@ where size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: tcx.data_layout.i8_align.abi, + randomization_seed: 0, }) } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index 9f138cf1275..fae787f9a40 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -347,6 +347,7 @@ fn layout_of_uncached<'tcx>( size, max_repr_align: None, unadjusted_abi_align: element.align.abi, + randomization_seed: element.randomization_seed.wrapping_add(count), }) } ty::Slice(element) => { @@ -360,6 +361,8 @@ fn layout_of_uncached<'tcx>( size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: element.align.abi, + // adding a randomly chosen value to distinguish slices + randomization_seed: element.randomization_seed.wrapping_add(0x2dcba99c39784102), }) } ty::Str => tcx.mk_layout(LayoutData { @@ -371,6 +374,8 @@ fn layout_of_uncached<'tcx>( size: Size::ZERO, max_repr_align: None, unadjusted_abi_align: dl.i8_align.abi, + // another random value + randomization_seed: 0xc1325f37d127be22, }), // Odd unit types. @@ -542,6 +547,7 @@ fn layout_of_uncached<'tcx>( align, max_repr_align: None, unadjusted_abi_align: align.abi, + randomization_seed: e_ly.randomization_seed.wrapping_add(e_len), }) } @@ -999,6 +1005,9 @@ fn coroutine_layout<'tcx>( BackendRepr::Memory { sized: true } }; + // this is similar to how ReprOptions populates its field_shuffle_seed + let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash().as_u64(); + let layout = tcx.mk_layout(LayoutData { variants: Variants::Multiple { tag, @@ -1019,6 +1028,7 @@ fn coroutine_layout<'tcx>( align, max_repr_align: None, unadjusted_abi_align: align.abi, + randomization_seed: def_hash, }); debug!("coroutine layout ({:?}): {:#?}", ty, layout); Ok(layout) |
