Skip to content

Commit

Permalink
Auto merge of rust-lang#133088 - the8472:randomize-me-harder, r=<try>
Browse files Browse the repository at this point in the history
`-Zrandomize-layout` harder. `Foo<T> != Foo<U>`

Tracking issue: rust-lang#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.
  • Loading branch information
bors committed Nov 24, 2024
2 parents e48241b + c276116 commit 0e4cbcd
Show file tree
Hide file tree
Showing 36 changed files with 333 additions and 66 deletions.
49 changes: 42 additions & 7 deletions compiler/rustc_abi/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -131,6 +133,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
size,
max_repr_align: None,
unadjusted_abi_align: align.abi,
randomization_seed: combined_seed,
}
}

Expand Down Expand Up @@ -222,6 +225,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
size: Size::ZERO,
max_repr_align: None,
unadjusted_abi_align: dl.i8_align.abi,
randomization_seed: 0,
}
}

Expand Down Expand Up @@ -384,6 +388,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),
Expand All @@ -393,6 +402,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
size: size.align_to(align.abi),
max_repr_align,
unadjusted_abi_align,
randomization_seed: combined_seed,
})
}

Expand Down Expand Up @@ -649,6 +659,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,
Expand All @@ -670,6 +685,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
align,
max_repr_align,
unadjusted_abi_align,
randomization_seed: combined_seed,
};

Some(TmpLayout { layout, variants: variant_layouts })
Expand Down Expand Up @@ -960,6 +976,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,
Expand All @@ -977,6 +998,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 };
Expand Down Expand Up @@ -1029,12 +1051,14 @@ 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];
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.
Expand All @@ -1043,10 +1067,12 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
{
use rand::SeedableRng;
use rand::seq::SliceRandom;
//let field_entropy = fields_excluding_tail.iter().map(|f| f.).sum();
// `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);
Expand Down Expand Up @@ -1343,6 +1369,14 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
unadjusted_abi_align
};

// a transparent struct only has a single field, so its seed should be the same as the one we pass forward
// if the field is also unsizable then we pass zero, which is the identity-element wrapping-add used for seed mixing
let seed = if repr.transparent() {
field_seed
} else {
field_seed.wrapping_add(repr.field_shuffle_seed)
};

Ok(LayoutData {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Arbitrary { offsets, memory_index },
Expand All @@ -1352,6 +1386,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
size,
max_repr_align,
unadjusted_abi_align,
randomization_seed: seed,
})
}

Expand Down
14 changes: 14 additions & 0 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1667,6 +1667,9 @@ 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'.
pub randomization_seed: u64,
}

impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
Expand All @@ -1687,6 +1690,14 @@ 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 seed_extra = match scalar.primitive() {
Primitive::Int(_, true) => 1,
Primitive::Int(_, false) => 2,
Primitive::Float(_) => 3,
Primitive::Pointer(_) => 4,
};

LayoutData {
variants: Variants::Single { index: VariantIdx::new(0) },
fields: FieldsShape::Primitive,
Expand All @@ -1696,6 +1707,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
align,
max_repr_align: None,
unadjusted_abi_align: align.abi,
randomization_seed: size.bytes().wrapping_add(seed_extra << 32),
}
}
}
Expand All @@ -1718,6 +1730,7 @@ where
variants,
max_repr_align,
unadjusted_abi_align,
ref randomization_seed,
} = self;
f.debug_struct("Layout")
.field("size", size)
Expand All @@ -1728,6 +1741,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()
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,7 @@ where
size: Size::ZERO,
max_repr_align: None,
unadjusted_abi_align: tcx.data_layout.i8_align.abi,
randomization_seed: 0,
})
}

Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_ty_utils/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,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) => {
Expand All @@ -361,6 +362,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 {
Expand All @@ -372,6 +375,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.
Expand Down Expand Up @@ -543,6 +548,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),
})
}

Expand Down Expand Up @@ -995,6 +1001,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,
Expand All @@ -1015,6 +1024,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)
Expand Down
4 changes: 4 additions & 0 deletions src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ fn layout_of_simd_ty(
align,
max_repr_align: None,
unadjusted_abi_align: align.abi,
randomization_seed: 0,
}))
}

Expand Down Expand Up @@ -313,6 +314,7 @@ pub fn layout_of_ty_query(
size,
max_repr_align: None,
unadjusted_abi_align: element.align.abi,
randomization_seed: 0,
}
}
TyKind::Slice(element) => {
Expand All @@ -326,6 +328,7 @@ pub fn layout_of_ty_query(
size: Size::ZERO,
max_repr_align: None,
unadjusted_abi_align: element.align.abi,
randomization_seed: 0,
}
}
TyKind::Str => Layout {
Expand All @@ -337,6 +340,7 @@ pub fn layout_of_ty_query(
size: Size::ZERO,
max_repr_align: None,
unadjusted_abi_align: dl.i8_align.abi,
randomization_seed: 0,
},
// Potentially-wide pointers.
TyKind::Ref(_, _, pointee) | TyKind::Raw(_, pointee) => {
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/abi/c-zst.aarch64-darwin.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Ignore,
Expand Down Expand Up @@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Ignore,
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/abi/c-zst.powerpc-linux.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Indirect {
Expand Down Expand Up @@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Ignore,
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/abi/c-zst.s390x-linux.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Indirect {
Expand Down Expand Up @@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Ignore,
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/abi/c-zst.sparc64-linux.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Indirect {
Expand Down Expand Up @@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Ignore,
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/abi/c-zst.x86_64-linux.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Ignore,
Expand Down Expand Up @@ -49,6 +50,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Ignore,
Expand Down
2 changes: 2 additions & 0 deletions tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Indirect {
Expand Down Expand Up @@ -60,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi {
},
max_repr_align: None,
unadjusted_abi_align: $SOME_ALIGN,
randomization_seed: 0,
},
},
mode: Ignore,
Expand Down
1 change: 1 addition & 0 deletions tests/ui/abi/debug.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//@ normalize-stderr-test: "(abi|pref|unadjusted_abi_align): Align\([1-8] bytes\)" -> "$1: $$SOME_ALIGN"
//@ normalize-stderr-test: "randomization_seed: \d+" -> "randomization_seed: $$SEED"
//@ normalize-stderr-test: "(size): Size\([48] bytes\)" -> "$1: $$SOME_SIZE"
//@ normalize-stderr-test: "(can_unwind): (true|false)" -> "$1: $$SOME_BOOL"
//@ normalize-stderr-test: "(valid_range): 0\.\.=(4294967295|18446744073709551615)" -> "$1: $$FULL"
Expand Down
Loading

0 comments on commit 0e4cbcd

Please sign in to comment.