Skip to content

Commit

Permalink
Auto merge of #135319 - matthiaskrgr:rollup-un5lol6, r=matthiaskrgr
Browse files Browse the repository at this point in the history
Rollup of 8 pull requests

Successful merges:

 - #133088 (`-Zrandomize-layout` harder. `Foo<T> != Foo<U>`)
 - #134619 (Improve prose around `as_slice` example of IterMut)
 - #134855 (Add `default_field_values` entry to unstable book)
 - #134908 (Fix `ptr::from_ref` documentation example comment)
 - #135275 (Add Pin::as_deref_mut to 1.84 relnotes)
 - #135294 (Make `bare-fn-no-impl-fn-ptr-99875` test less dependent on path width)
 - #135304 (Add tests cases from review of #132289)
 - #135308 (Make sure to walk into nested const blocks in `RegionResolutionVisitor`)

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Jan 10, 2025
2 parents 88ab2d8 + c51bfaf commit 67951d9
Show file tree
Hide file tree
Showing 53 changed files with 738 additions and 124 deletions.
1 change: 1 addition & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Stabilized APIs
- [`core::ptr::without_provenance_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.without_provenance_mut.html)
- [`core::ptr::dangling`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling.html)
- [`core::ptr::dangling_mut`](https://doc.rust-lang.org/stable/core/ptr/fn.dangling_mut.html)
- [`Pin::as_deref_mut`](https://doc.rust-lang.org/stable/core/pin/struct.Pin.html#method.as_deref_mut)

These APIs are now stable in const contexts

Expand Down
43 changes: 36 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 @@ -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,
}
}

Expand Down Expand Up @@ -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),
Expand All @@ -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,
})
}

Expand Down Expand Up @@ -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,
Expand All @@ -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 })
Expand Down Expand Up @@ -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,
Expand All @@ -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 };
Expand Down Expand Up @@ -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.
Expand All @@ -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);
Expand Down Expand Up @@ -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 },
Expand All @@ -1353,6 +1381,7 @@ impl<Cx: HasDataLayout> LayoutCalculator<Cx> {
size,
max_repr_align,
unadjusted_abi_align,
randomization_seed: seed,
})
}

Expand Down
39 changes: 39 additions & 0 deletions compiler/rustc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand All @@ -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,
Expand All @@ -1748,6 +1784,7 @@ impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
align,
max_repr_align: None,
unadjusted_abi_align: align.abi,
randomization_seed,
}
}
}
Expand All @@ -1770,6 +1807,7 @@ where
variants,
max_repr_align,
unadjusted_abi_align,
ref randomization_seed,
} = self;
f.debug_struct("Layout")
.field("size", size)
Expand All @@ -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()
}
}
Expand Down
36 changes: 20 additions & 16 deletions compiler/rustc_hir_analysis/src/check/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ struct Context {
parent: Option<(Scope, ScopeDepth)>,
}

struct RegionResolutionVisitor<'tcx> {
struct ScopeResolutionVisitor<'tcx> {
tcx: TyCtxt<'tcx>,

// The number of expressions and patterns visited in the current body.
Expand Down Expand Up @@ -71,7 +71,7 @@ struct RegionResolutionVisitor<'tcx> {
}

/// Records the lifetime of a local variable as `cx.var_parent`
fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::ItemLocalId) {
fn record_var_lifetime(visitor: &mut ScopeResolutionVisitor<'_>, var_id: hir::ItemLocalId) {
match visitor.cx.var_parent {
None => {
// this can happen in extern fn declarations like
Expand All @@ -82,7 +82,7 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::I
}
}

fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx hir::Block<'tcx>) {
fn resolve_block<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, blk: &'tcx hir::Block<'tcx>) {
debug!("resolve_block(blk.hir_id={:?})", blk.hir_id);

let prev_cx = visitor.cx;
Expand Down Expand Up @@ -193,7 +193,7 @@ fn resolve_block<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, blk: &'tcx h
visitor.cx = prev_cx;
}

fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
fn resolve_arm<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, arm: &'tcx hir::Arm<'tcx>) {
fn has_let_expr(expr: &Expr<'_>) -> bool {
match &expr.kind {
hir::ExprKind::Binary(_, lhs, rhs) => has_let_expr(lhs) || has_let_expr(rhs),
Expand All @@ -220,7 +220,7 @@ fn resolve_arm<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, arm: &'tcx hir
visitor.cx = prev_cx;
}

fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
fn resolve_pat<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
visitor.record_child_scope(Scope { local_id: pat.hir_id.local_id, data: ScopeData::Node });

// If this is a binding then record the lifetime of that binding.
Expand All @@ -237,7 +237,7 @@ fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir
debug!("resolve_pat - post-increment {} pat = {:?}", visitor.expr_and_pat_count, pat);
}

fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx hir::Stmt<'tcx>) {
fn resolve_stmt<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, stmt: &'tcx hir::Stmt<'tcx>) {
let stmt_id = stmt.hir_id.local_id;
debug!("resolve_stmt(stmt.id={:?})", stmt_id);

Expand All @@ -256,7 +256,7 @@ fn resolve_stmt<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, stmt: &'tcx h
visitor.cx.parent = prev_parent;
}

fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
fn resolve_expr<'tcx>(visitor: &mut ScopeResolutionVisitor<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
debug!("resolve_expr - pre-increment {} expr = {:?}", visitor.expr_and_pat_count, expr);

let prev_cx = visitor.cx;
Expand Down Expand Up @@ -420,10 +420,10 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
// properly, we can't miss any types.

match expr.kind {
// Manually recurse over closures and inline consts, because they are the only
// case of nested bodies that share the parent environment.
hir::ExprKind::Closure(&hir::Closure { body, .. })
| hir::ExprKind::ConstBlock(hir::ConstBlock { body, .. }) => {
// Manually recurse over closures, because they are nested bodies
// that share the parent environment. We handle const blocks in
// `visit_inline_const`.
hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
let body = visitor.tcx.hir().body(body);
visitor.visit_body(body);
}
Expand Down Expand Up @@ -554,7 +554,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
}

fn resolve_local<'tcx>(
visitor: &mut RegionResolutionVisitor<'tcx>,
visitor: &mut ScopeResolutionVisitor<'tcx>,
pat: Option<&'tcx hir::Pat<'tcx>>,
init: Option<&'tcx hir::Expr<'tcx>>,
) {
Expand Down Expand Up @@ -725,7 +725,7 @@ fn resolve_local<'tcx>(
/// | ( E& )
/// ```
fn record_rvalue_scope_if_borrow_expr<'tcx>(
visitor: &mut RegionResolutionVisitor<'tcx>,
visitor: &mut ScopeResolutionVisitor<'tcx>,
expr: &hir::Expr<'_>,
blk_id: Option<Scope>,
) {
Expand Down Expand Up @@ -782,7 +782,7 @@ fn resolve_local<'tcx>(
}
}

impl<'tcx> RegionResolutionVisitor<'tcx> {
impl<'tcx> ScopeResolutionVisitor<'tcx> {
/// Records the current parent (if any) as the parent of `child_scope`.
/// Returns the depth of `child_scope`.
fn record_child_scope(&mut self, child_scope: Scope) -> ScopeDepth {
Expand Down Expand Up @@ -838,7 +838,7 @@ impl<'tcx> RegionResolutionVisitor<'tcx> {
}
}

impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
impl<'tcx> Visitor<'tcx> for ScopeResolutionVisitor<'tcx> {
fn visit_block(&mut self, b: &'tcx Block<'tcx>) {
resolve_block(self, b);
}
Expand Down Expand Up @@ -906,6 +906,10 @@ impl<'tcx> Visitor<'tcx> for RegionResolutionVisitor<'tcx> {
fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) {
resolve_local(self, Some(l.pat), l.init)
}
fn visit_inline_const(&mut self, c: &'tcx hir::ConstBlock) {
let body = self.tcx.hir().body(c.body);
self.visit_body(body);
}
}

/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
Expand All @@ -922,7 +926,7 @@ pub(crate) fn region_scope_tree(tcx: TyCtxt<'_>, def_id: DefId) -> &ScopeTree {
}

let scope_tree = if let Some(body) = tcx.hir().maybe_body_owned_by(def_id.expect_local()) {
let mut visitor = RegionResolutionVisitor {
let mut visitor = ScopeResolutionVisitor {
tcx,
scope_tree: ScopeTree::default(),
expr_and_pat_count: 0,
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 @@ -770,6 +770,7 @@ where
size: Size::ZERO,
max_repr_align: None,
unadjusted_abi_align: tcx.data_layout.i8_align.abi,
randomization_seed: 0,
})
}

Expand Down
Loading

0 comments on commit 67951d9

Please sign in to comment.