Skip to content

Commit ca164e5

Browse files
committed
Foo<T> != Foo<U> under layout randomization
previously field ordering was using the same seed for all instances of Foo, now we pass seed values through the layout tree so that not only the struct itself affects layout but also its fields
1 parent 917a50a commit ca164e5

File tree

5 files changed

+90
-2
lines changed

5 files changed

+90
-2
lines changed

compiler/rustc_abi/src/layout.rs

+36-2
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
119119
.chain(Niche::from_scalar(dl, Size::ZERO, a))
120120
.max_by_key(|niche| niche.available(dl));
121121

122+
let combined_seed = a.size(&self.cx).bytes().wrapping_add(b.size(&self.cx).bytes());
123+
122124
LayoutData {
123125
variants: Variants::Single { index: VariantIdx::new(0) },
124126
fields: FieldsShape::Arbitrary {
@@ -131,6 +133,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
131133
size,
132134
max_repr_align: None,
133135
unadjusted_abi_align: align.abi,
136+
randomization_seed: combined_seed,
134137
}
135138
}
136139

@@ -222,6 +225,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
222225
size: Size::ZERO,
223226
max_repr_align: None,
224227
unadjusted_abi_align: dl.i8_align.abi,
228+
randomization_seed: 0,
225229
}
226230
}
227231

@@ -384,6 +388,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
384388
return Err(LayoutCalculatorError::EmptyUnion);
385389
};
386390

391+
let combined_seed = only_variant
392+
.iter()
393+
.map(|v| v.randomization_seed)
394+
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
395+
387396
Ok(LayoutData {
388397
variants: Variants::Single { index: only_variant_idx },
389398
fields: FieldsShape::Union(union_field_count),
@@ -393,6 +402,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
393402
size: size.align_to(align.abi),
394403
max_repr_align,
395404
unadjusted_abi_align,
405+
randomization_seed: combined_seed,
396406
})
397407
}
398408

@@ -649,6 +659,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
649659
BackendRepr::Memory { sized: true }
650660
};
651661

662+
let combined_seed = variant_layouts
663+
.iter()
664+
.map(|v| v.randomization_seed)
665+
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
666+
652667
let layout = LayoutData {
653668
variants: Variants::Multiple {
654669
tag: niche_scalar,
@@ -670,6 +685,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
670685
align,
671686
max_repr_align,
672687
unadjusted_abi_align,
688+
randomization_seed: combined_seed,
673689
};
674690

675691
Some(TmpLayout { layout, variants: variant_layouts })
@@ -960,6 +976,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
960976

961977
let largest_niche = Niche::from_scalar(dl, Size::ZERO, tag);
962978

979+
let combined_seed = layout_variants
980+
.iter()
981+
.map(|v| v.randomization_seed)
982+
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
983+
963984
let tagged_layout = LayoutData {
964985
variants: Variants::Multiple {
965986
tag,
@@ -977,6 +998,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
977998
size,
978999
max_repr_align,
9791000
unadjusted_abi_align,
1001+
randomization_seed: combined_seed,
9801002
};
9811003

9821004
let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
@@ -1028,6 +1050,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
10281050
let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
10291051
let mut max_repr_align = repr.align;
10301052
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
1053+
let field_seed =
1054+
fields.raw.iter().fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed));
10311055
let optimize_field_order = !repr.inhibit_struct_field_reordering();
10321056
if optimize_field_order && fields.len() > 1 {
10331057
let end =
@@ -1043,10 +1067,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
10431067
{
10441068
use rand::SeedableRng;
10451069
use rand::seq::SliceRandom;
1070+
//let field_entropy = fields_excluding_tail.iter().map(|f| f.).sum();
10461071
// `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field
10471072
// ordering.
1048-
let mut rng =
1049-
rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
1073+
let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64(
1074+
field_seed.wrapping_add(repr.field_shuffle_seed),
1075+
);
10501076

10511077
// Shuffle the ordering of the fields.
10521078
optimizing.shuffle(&mut rng);
@@ -1343,6 +1369,13 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
13431369
unadjusted_abi_align
13441370
};
13451371

1372+
// a transparent struct only has a single field, so its seed should be the same as the one we pass forward
1373+
let seed = if repr.transparent() {
1374+
field_seed
1375+
} else {
1376+
field_seed.wrapping_add(repr.field_shuffle_seed)
1377+
};
1378+
13461379
Ok(LayoutData {
13471380
variants: Variants::Single { index: VariantIdx::new(0) },
13481381
fields: FieldsShape::Arbitrary { offsets, memory_index },
@@ -1352,6 +1385,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
13521385
size,
13531386
max_repr_align,
13541387
unadjusted_abi_align,
1388+
randomization_seed: seed,
13551389
})
13561390
}
13571391

compiler/rustc_abi/src/lib.rs

+14
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,9 @@ pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
16671667
/// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment
16681668
/// in some cases.
16691669
pub unadjusted_abi_align: Align,
1670+
1671+
/// The randomization seed based on this type's own repr and its fields'.
1672+
pub randomization_seed: u64,
16701673
}
16711674

16721675
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
@@ -1687,6 +1690,14 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
16871690
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
16881691
let size = scalar.size(cx);
16891692
let align = scalar.align(cx);
1693+
1694+
let seed_extra = match scalar.primitive() {
1695+
Primitive::Int(_, true) => 1,
1696+
Primitive::Int(_, false) => 2,
1697+
Primitive::Float(_) => 3,
1698+
Primitive::Pointer(_) => 4,
1699+
};
1700+
16901701
LayoutData {
16911702
variants: Variants::Single { index: VariantIdx::new(0) },
16921703
fields: FieldsShape::Primitive,
@@ -1696,6 +1707,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
16961707
align,
16971708
max_repr_align: None,
16981709
unadjusted_abi_align: align.abi,
1710+
randomization_seed: size.bytes().wrapping_add(seed_extra << 32),
16991711
}
17001712
}
17011713
}
@@ -1718,6 +1730,7 @@ where
17181730
variants,
17191731
max_repr_align,
17201732
unadjusted_abi_align,
1733+
ref randomization_seed,
17211734
} = self;
17221735
f.debug_struct("Layout")
17231736
.field("size", size)
@@ -1728,6 +1741,7 @@ where
17281741
.field("variants", variants)
17291742
.field("max_repr_align", max_repr_align)
17301743
.field("unadjusted_abi_align", unadjusted_abi_align)
1744+
.field("randomization_seed", randomization_seed)
17311745
.finish()
17321746
}
17331747
}

compiler/rustc_middle/src/ty/layout.rs

+1
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,7 @@ where
761761
size: Size::ZERO,
762762
max_repr_align: None,
763763
unadjusted_abi_align: tcx.data_layout.i8_align.abi,
764+
randomization_seed: 0,
764765
})
765766
}
766767

compiler/rustc_ty_utils/src/layout.rs

+10
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ fn layout_of_uncached<'tcx>(
348348
size,
349349
max_repr_align: None,
350350
unadjusted_abi_align: element.align.abi,
351+
randomization_seed: element.randomization_seed.wrapping_add(count),
351352
})
352353
}
353354
ty::Slice(element) => {
@@ -361,6 +362,8 @@ fn layout_of_uncached<'tcx>(
361362
size: Size::ZERO,
362363
max_repr_align: None,
363364
unadjusted_abi_align: element.align.abi,
365+
// adding a randomly chosen value to distinguish slices
366+
randomization_seed: element.randomization_seed.wrapping_add(0x2dcba99c39784102),
364367
})
365368
}
366369
ty::Str => tcx.mk_layout(LayoutData {
@@ -372,6 +375,8 @@ fn layout_of_uncached<'tcx>(
372375
size: Size::ZERO,
373376
max_repr_align: None,
374377
unadjusted_abi_align: dl.i8_align.abi,
378+
// another random value
379+
randomization_seed: 0xc1325f37d127be22,
375380
}),
376381

377382
// Odd unit types.
@@ -543,6 +548,7 @@ fn layout_of_uncached<'tcx>(
543548
align,
544549
max_repr_align: None,
545550
unadjusted_abi_align: align.abi,
551+
randomization_seed: e_ly.randomization_seed.wrapping_add(e_len),
546552
})
547553
}
548554

@@ -995,6 +1001,9 @@ fn coroutine_layout<'tcx>(
9951001
BackendRepr::Memory { sized: true }
9961002
};
9971003

1004+
// this is similar to how ReprOptions populates its field_shuffle_seed
1005+
let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash().as_u64();
1006+
9981007
let layout = tcx.mk_layout(LayoutData {
9991008
variants: Variants::Multiple {
10001009
tag,
@@ -1015,6 +1024,7 @@ fn coroutine_layout<'tcx>(
10151024
align,
10161025
max_repr_align: None,
10171026
unadjusted_abi_align: align.abi,
1027+
randomization_seed: def_hash,
10181028
});
10191029
debug!("coroutine layout ({:?}): {:#?}", ty, layout);
10201030
Ok(layout)

tests/ui/layout/randomize.rs

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//@ build-pass
2+
//@ revisions: normal randomize-layout
3+
//@ [randomize-layout]compile-flags: -Zrandomize-layout
4+
5+
#![crate_type = "lib"]
6+
7+
struct Foo<T>(u32, T, u8);
8+
9+
struct Wrapper<T>(T);
10+
11+
#[repr(transparent)]
12+
struct TransparentWrapper(u16);
13+
14+
const _: () = {
15+
// behavior of the current implementation, not guaranteed
16+
#[cfg(not(randomize_layout))]
17+
assert!(std::mem::offset_of!(Foo::<u16>, 1) == std::mem::offset_of!(Foo::<Wrapper<u16>>, 1));
18+
19+
// under randomization Foo<T> != Foo<U>
20+
#[cfg(randomize_layout)]
21+
assert!(std::mem::offset_of!(Foo::<u16>, 1) != std::mem::offset_of!(Foo::<Wrapper<u16>>, 1));
22+
23+
// but repr(transparent) should make them the same again.
24+
// maybe not strictly guaranteed? but UCG has been leaning in that direction at least
25+
#[cfg(randomize_layout)]
26+
assert!(
27+
std::mem::offset_of!(Foo::<u16>, 1) == std::mem::offset_of!(Foo::<TransparentWrapper>, 1)
28+
);
29+
};

0 commit comments

Comments
 (0)