Skip to content

Commit

Permalink
Rollup merge of #118540 - RalfJung:unsized-packed-offset, r=TaKO8Ki
Browse files Browse the repository at this point in the history
codegen, miri: fix computing the offset of an unsized field in a packed struct

`#[repr(packed)]`  strikes again.

Fixes rust-lang/rust#118537
Fixes #3200

`@bjorn3` I assume cranelift needs the same fix.
  • Loading branch information
TaKO8Ki authored Dec 4, 2023
2 parents 05de086 + 06dc9f2 commit 96aff94
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 0 deletions.
35 changes: 35 additions & 0 deletions tests/pass/issues/issue-3200-packed-field-offset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#![feature(layout_for_ptr)]
use std::mem;

#[repr(packed, C)]
struct PackedSized {
f: u8,
d: [u32; 4],
}

#[repr(packed, C)]
struct PackedUnsized {
f: u8,
d: [u32],
}

impl PackedSized {
fn unsize(&self) -> &PackedUnsized {
// We can't unsize via a generic type since then we get the error
// that packed structs with unsized tail don't work if the tail
// might need dropping.
let len = 4usize;
unsafe { mem::transmute((self, len)) }
}
}

fn main() { unsafe {
let p = PackedSized { f: 0, d: [1, 2, 3, 4] };
let p = p.unsize() as *const PackedUnsized;
// Make sure the size computation does *not* think there is
// any padding in front of the `d` field.
assert_eq!(mem::size_of_val_raw(p), 1 + 4*4);
// And likewise for the offset computation.
let d = std::ptr::addr_of!((*p).d);
assert_eq!(d.cast::<u32>().read_unaligned(), 1);
} }
38 changes: 38 additions & 0 deletions tests/pass/issues/issue-3200-packed2-field-offset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#![feature(layout_for_ptr)]
use std::mem;

#[repr(packed(4))]
struct Slice([u32]);

#[repr(packed(2), C)]
struct PackedSized {
f: u8,
d: [u32; 4],
}

#[repr(packed(2), C)]
struct PackedUnsized {
f: u8,
d: Slice,
}

impl PackedSized {
fn unsize(&self) -> &PackedUnsized {
// We can't unsize via a generic type since then we get the error
// that packed structs with unsized tail don't work if the tail
// might need dropping.
let len = 4usize;
unsafe { mem::transmute((self, len)) }
}
}

fn main() { unsafe {
let p = PackedSized { f: 0, d: [1, 2, 3, 4] };
let p = p.unsize() as *const PackedUnsized;
// Make sure the size computation correctly adds exact 1 byte of padding
// in front of the `d` field.
assert_eq!(mem::size_of_val_raw(p), 1 + 1 + 4*4);
// And likewise for the offset computation.
let d = std::ptr::addr_of!((*p).d);
assert_eq!(d.cast::<u32>().read_unaligned(), 1);
} }

0 comments on commit 96aff94

Please sign in to comment.