Skip to content

Commit 0e4cbcd

Browse files
committed
Auto merge of #133088 - the8472:randomize-me-harder, r=<try>
`-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.
2 parents e48241b + c276116 commit 0e4cbcd

36 files changed

+333
-66
lines changed

compiler/rustc_abi/src/layout.rs

+42-7
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 };
@@ -1029,12 +1051,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
10291051
let mut max_repr_align = repr.align;
10301052
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
10311053
let optimize_field_order = !repr.inhibit_struct_field_reordering();
1032-
if optimize_field_order && fields.len() > 1 {
1033-
let end =
1034-
if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
1035-
let optimizing = &mut inverse_memory_index.raw[..end];
1036-
let fields_excluding_tail = &fields.raw[..end];
1054+
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
1055+
let optimizing = &mut inverse_memory_index.raw[..end];
1056+
let fields_excluding_tail = &fields.raw[..end];
1057+
let field_seed = fields_excluding_tail
1058+
.iter()
1059+
.fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed));
10371060

1061+
if optimize_field_order && fields.len() > 1 {
10381062
// If `-Z randomize-layout` was enabled for the type definition we can shuffle
10391063
// the field ordering to try and catch some code making assumptions about layouts
10401064
// we don't guarantee.
@@ -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,14 @@ 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+
// if the field is also unsizable then we pass zero, which is the identity-element wrapping-add used for seed mixing
1374+
let seed = if repr.transparent() {
1375+
field_seed
1376+
} else {
1377+
field_seed.wrapping_add(repr.field_shuffle_seed)
1378+
};
1379+
13461380
Ok(LayoutData {
13471381
variants: Variants::Single { index: VariantIdx::new(0) },
13481382
fields: FieldsShape::Arbitrary { offsets, memory_index },
@@ -1352,6 +1386,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
13521386
size,
13531387
max_repr_align,
13541388
unadjusted_abi_align,
1389+
randomization_seed: seed,
13551390
})
13561391
}
13571392

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
@@ -767,6 +767,7 @@ where
767767
size: Size::ZERO,
768768
max_repr_align: None,
769769
unadjusted_abi_align: tcx.data_layout.i8_align.abi,
770+
randomization_seed: 0,
770771
})
771772
}
772773

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)

src/tools/rust-analyzer/crates/hir-ty/src/layout.rs

+4
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ fn layout_of_simd_ty(
197197
align,
198198
max_repr_align: None,
199199
unadjusted_abi_align: align.abi,
200+
randomization_seed: 0,
200201
}))
201202
}
202203

@@ -313,6 +314,7 @@ pub fn layout_of_ty_query(
313314
size,
314315
max_repr_align: None,
315316
unadjusted_abi_align: element.align.abi,
317+
randomization_seed: 0,
316318
}
317319
}
318320
TyKind::Slice(element) => {
@@ -326,6 +328,7 @@ pub fn layout_of_ty_query(
326328
size: Size::ZERO,
327329
max_repr_align: None,
328330
unadjusted_abi_align: element.align.abi,
331+
randomization_seed: 0,
329332
}
330333
}
331334
TyKind::Str => Layout {
@@ -337,6 +340,7 @@ pub fn layout_of_ty_query(
337340
size: Size::ZERO,
338341
max_repr_align: None,
339342
unadjusted_abi_align: dl.i8_align.abi,
343+
randomization_seed: 0,
340344
},
341345
// Potentially-wide pointers.
342346
TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {

tests/ui/abi/c-zst.aarch64-darwin.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
2222
},
2323
max_repr_align: None,
2424
unadjusted_abi_align: $SOME_ALIGN,
25+
randomization_seed: 0,
2526
},
2627
},
2728
mode: Ignore,
@@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
4950
},
5051
max_repr_align: None,
5152
unadjusted_abi_align: $SOME_ALIGN,
53+
randomization_seed: 0,
5254
},
5355
},
5456
mode: Ignore,

tests/ui/abi/c-zst.powerpc-linux.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
2222
},
2323
max_repr_align: None,
2424
unadjusted_abi_align: $SOME_ALIGN,
25+
randomization_seed: 0,
2526
},
2627
},
2728
mode: Indirect {
@@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
6061
},
6162
max_repr_align: None,
6263
unadjusted_abi_align: $SOME_ALIGN,
64+
randomization_seed: 0,
6365
},
6466
},
6567
mode: Ignore,

tests/ui/abi/c-zst.s390x-linux.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
2222
},
2323
max_repr_align: None,
2424
unadjusted_abi_align: $SOME_ALIGN,
25+
randomization_seed: 0,
2526
},
2627
},
2728
mode: Indirect {
@@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
6061
},
6162
max_repr_align: None,
6263
unadjusted_abi_align: $SOME_ALIGN,
64+
randomization_seed: 0,
6365
},
6466
},
6567
mode: Ignore,

tests/ui/abi/c-zst.sparc64-linux.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
2222
},
2323
max_repr_align: None,
2424
unadjusted_abi_align: $SOME_ALIGN,
25+
randomization_seed: 0,
2526
},
2627
},
2728
mode: Indirect {
@@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
6061
},
6162
max_repr_align: None,
6263
unadjusted_abi_align: $SOME_ALIGN,
64+
randomization_seed: 0,
6365
},
6466
},
6567
mode: Ignore,

tests/ui/abi/c-zst.x86_64-linux.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
2222
},
2323
max_repr_align: None,
2424
unadjusted_abi_align: $SOME_ALIGN,
25+
randomization_seed: 0,
2526
},
2627
},
2728
mode: Ignore,
@@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
4950
},
5051
max_repr_align: None,
5152
unadjusted_abi_align: $SOME_ALIGN,
53+
randomization_seed: 0,
5254
},
5355
},
5456
mode: Ignore,

tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
2222
},
2323
max_repr_align: None,
2424
unadjusted_abi_align: $SOME_ALIGN,
25+
randomization_seed: 0,
2526
},
2627
},
2728
mode: Indirect {
@@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
6061
},
6162
max_repr_align: None,
6263
unadjusted_abi_align: $SOME_ALIGN,
64+
randomization_seed: 0,
6365
},
6466
},
6567
mode: Ignore,

tests/ui/abi/debug.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//@ normalize-stderr-test: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
2+
//@ normalize-stderr-test: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
23
//@ normalize-stderr-test: "(size): Size\([48] bytes\)" -> "$1: $$SOME_SIZE"
34
//@ normalize-stderr-test: "(can_unwind): (true|false)" -> "$1: $$SOME_BOOL"
45
//@ normalize-stderr-test: "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL"

0 commit comments

Comments
 (0)