Skip to content

Commit eaf4206

Browse files
authored
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.
2 parents 62bf38f + d89b6d5 commit eaf4206

39 files changed

+400
-78
lines changed

compiler/rustc_abi/src/layout.rs

+36-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

@@ -223,6 +226,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
223226
size: Size::ZERO,
224227
max_repr_align: None,
225228
unadjusted_abi_align: dl.i8_align.abi,
229+
randomization_seed: 0,
226230
}
227231
}
228232

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

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

@@ -650,6 +660,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
650660
BackendRepr::Memory { sized: true }
651661
};
652662

663+
let combined_seed = variant_layouts
664+
.iter()
665+
.map(|v| v.randomization_seed)
666+
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
667+
653668
let layout = LayoutData {
654669
variants: Variants::Multiple {
655670
tag: niche_scalar,
@@ -671,6 +686,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
671686
align,
672687
max_repr_align,
673688
unadjusted_abi_align,
689+
randomization_seed: combined_seed,
674690
};
675691

676692
Some(TmpLayout { layout, variants: variant_layouts })
@@ -961,6 +977,11 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
961977

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

980+
let combined_seed = layout_variants
981+
.iter()
982+
.map(|v| v.randomization_seed)
983+
.fold(repr.field_shuffle_seed, |acc, seed| acc.wrapping_add(seed));
984+
964985
let tagged_layout = LayoutData {
965986
variants: Variants::Multiple {
966987
tag,
@@ -978,6 +999,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
978999
size,
9791000
max_repr_align,
9801001
unadjusted_abi_align,
1002+
randomization_seed: combined_seed,
9811003
};
9821004

9831005
let tagged_layout = TmpLayout { layout: tagged_layout, variants: layout_variants };
@@ -1030,12 +1052,15 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
10301052
let mut max_repr_align = repr.align;
10311053
let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
10321054
let optimize_field_order = !repr.inhibit_struct_field_reordering();
1033-
if optimize_field_order && fields.len() > 1 {
1034-
let end =
1035-
if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
1036-
let optimizing = &mut inverse_memory_index.raw[..end];
1037-
let fields_excluding_tail = &fields.raw[..end];
1055+
let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
1056+
let optimizing = &mut inverse_memory_index.raw[..end];
1057+
let fields_excluding_tail = &fields.raw[..end];
1058+
// unsizable tail fields are excluded so that we use the same seed for the sized and unsized layouts.
1059+
let field_seed = fields_excluding_tail
1060+
.iter()
1061+
.fold(0u64, |acc, f| acc.wrapping_add(f.randomization_seed));
10381062

1063+
if optimize_field_order && fields.len() > 1 {
10391064
// If `-Z randomize-layout` was enabled for the type definition we can shuffle
10401065
// the field ordering to try and catch some code making assumptions about layouts
10411066
// we don't guarantee.
@@ -1046,8 +1071,9 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
10461071
use rand::seq::SliceRandom;
10471072
// `ReprOptions.field_shuffle_seed` is a deterministic seed we can use to randomize field
10481073
// ordering.
1049-
let mut rng =
1050-
rand_xoshiro::Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
1074+
let mut rng = rand_xoshiro::Xoshiro128StarStar::seed_from_u64(
1075+
field_seed.wrapping_add(repr.field_shuffle_seed),
1076+
);
10511077

10521078
// Shuffle the ordering of the fields.
10531079
optimizing.shuffle(&mut rng);
@@ -1344,6 +1370,8 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
13441370
unadjusted_abi_align
13451371
};
13461372

1373+
let seed = field_seed.wrapping_add(repr.field_shuffle_seed);
1374+
13471375
Ok(LayoutData {
13481376
variants: Variants::Single { index: VariantIdx::new(0) },
13491377
fields: FieldsShape::Arbitrary { offsets, memory_index },
@@ -1353,6 +1381,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
13531381
size,
13541382
max_repr_align,
13551383
unadjusted_abi_align,
1384+
randomization_seed: seed,
13561385
})
13571386
}
13581387

compiler/rustc_abi/src/lib.rs

+39
Original file line numberDiff line numberDiff line change
@@ -1719,6 +1719,18 @@ pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
17191719
/// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment
17201720
/// in some cases.
17211721
pub unadjusted_abi_align: Align,
1722+
1723+
/// The randomization seed based on this type's own repr and its fields.
1724+
///
1725+
/// Since randomization is toggled on a per-crate basis even crates that do not have randomization
1726+
/// enabled should still calculate a seed so that downstream uses can use it to distinguish different
1727+
/// types.
1728+
///
1729+
/// For every T and U for which we do not guarantee that a repr(Rust) `Foo<T>` can be coerced or
1730+
/// transmuted to `Foo<U>` we aim to create probalistically distinct seeds so that Foo can choose
1731+
/// to reorder its fields based on that information. The current implementation is a conservative
1732+
/// approximation of this goal.
1733+
pub randomization_seed: u64,
17221734
}
17231735

17241736
impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
@@ -1739,6 +1751,30 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
17391751
let largest_niche = Niche::from_scalar(cx, Size::ZERO, scalar);
17401752
let size = scalar.size(cx);
17411753
let align = scalar.align(cx);
1754+
1755+
let range = scalar.valid_range(cx);
1756+
1757+
// All primitive types for which we don't have subtype coercions should get a distinct seed,
1758+
// so that types wrapping them can use randomization to arrive at distinct layouts.
1759+
//
1760+
// Some type information is already lost at this point, so as an approximation we derive
1761+
// the seed from what remains. For example on 64-bit targets usize and u64 can no longer
1762+
// be distinguished.
1763+
let randomization_seed = size
1764+
.bytes()
1765+
.wrapping_add(
1766+
match scalar.primitive() {
1767+
Primitive::Int(_, true) => 1,
1768+
Primitive::Int(_, false) => 2,
1769+
Primitive::Float(_) => 3,
1770+
Primitive::Pointer(_) => 4,
1771+
} << 32,
1772+
)
1773+
// distinguishes references from pointers
1774+
.wrapping_add((range.start as u64).rotate_right(16))
1775+
// distinguishes char from u32 and bool from u8
1776+
.wrapping_add((range.end as u64).rotate_right(16));
1777+
17421778
LayoutData {
17431779
variants: Variants::Single { index: VariantIdx::new(0) },
17441780
fields: FieldsShape::Primitive,
@@ -1748,6 +1784,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
17481784
align,
17491785
max_repr_align: None,
17501786
unadjusted_abi_align: align.abi,
1787+
randomization_seed,
17511788
}
17521789
}
17531790
}
@@ -1770,6 +1807,7 @@ where
17701807
variants,
17711808
max_repr_align,
17721809
unadjusted_abi_align,
1810+
ref randomization_seed,
17731811
} = self;
17741812
f.debug_struct("Layout")
17751813
.field("size", size)
@@ -1780,6 +1818,7 @@ where
17801818
.field("variants", variants)
17811819
.field("max_repr_align", max_repr_align)
17821820
.field("unadjusted_abi_align", unadjusted_abi_align)
1821+
.field("randomization_seed", randomization_seed)
17831822
.finish()
17841823
}
17851824
}

compiler/rustc_middle/src/ty/layout.rs

+1
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ where
770770
size: Size::ZERO,
771771
max_repr_align: None,
772772
unadjusted_abi_align: tcx.data_layout.i8_align.abi,
773+
randomization_seed: 0,
773774
})
774775
}
775776

compiler/rustc_ty_utils/src/layout.rs

+10
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ fn layout_of_uncached<'tcx>(
347347
size,
348348
max_repr_align: None,
349349
unadjusted_abi_align: element.align.abi,
350+
randomization_seed: element.randomization_seed.wrapping_add(count),
350351
})
351352
}
352353
ty::Slice(element) => {
@@ -360,6 +361,8 @@ fn layout_of_uncached<'tcx>(
360361
size: Size::ZERO,
361362
max_repr_align: None,
362363
unadjusted_abi_align: element.align.abi,
364+
// adding a randomly chosen value to distinguish slices
365+
randomization_seed: element.randomization_seed.wrapping_add(0x2dcba99c39784102),
363366
})
364367
}
365368
ty::Str => tcx.mk_layout(LayoutData {
@@ -371,6 +374,8 @@ fn layout_of_uncached<'tcx>(
371374
size: Size::ZERO,
372375
max_repr_align: None,
373376
unadjusted_abi_align: dl.i8_align.abi,
377+
// another random value
378+
randomization_seed: 0xc1325f37d127be22,
374379
}),
375380

376381
// Odd unit types.
@@ -542,6 +547,7 @@ fn layout_of_uncached<'tcx>(
542547
align,
543548
max_repr_align: None,
544549
unadjusted_abi_align: align.abi,
550+
randomization_seed: e_ly.randomization_seed.wrapping_add(e_len),
545551
})
546552
}
547553

@@ -999,6 +1005,9 @@ fn coroutine_layout<'tcx>(
9991005
BackendRepr::Memory { sized: true }
10001006
};
10011007

1008+
// this is similar to how ReprOptions populates its field_shuffle_seed
1009+
let def_hash = tcx.def_path_hash(def_id).0.to_smaller_hash().as_u64();
1010+
10021011
let layout = tcx.mk_layout(LayoutData {
10031012
variants: Variants::Multiple {
10041013
tag,
@@ -1019,6 +1028,7 @@ fn coroutine_layout<'tcx>(
10191028
align,
10201029
max_repr_align: None,
10211030
unadjusted_abi_align: align.abi,
1031+
randomization_seed: def_hash,
10221032
});
10231033
debug!("coroutine layout ({:?}): {:#?}", ty, layout);
10241034
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,

0 commit comments

Comments
 (0)