Skip to content

Commit

Permalink
fix is_disaligned logic for nested packed structs
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Aug 3, 2022
1 parent bd84c73 commit 9097ce9
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 17 deletions.
28 changes: 12 additions & 16 deletions compiler/rustc_const_eval/src/util/alignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,16 @@ fn is_within_packed<'tcx, L>(
where
L: HasLocalDecls<'tcx>,
{
for (place_base, elem) in place.iter_projections().rev() {
match elem {
// encountered a Deref, which is ABI-aligned
ProjectionElem::Deref => break,
ProjectionElem::Field(..) => {
let ty = place_base.ty(local_decls, tcx).ty;
match ty.kind() {
ty::Adt(def, _) => return def.repr().pack,
_ => {}
}
}
_ => {}
}
}

None
place
.iter_projections()
.rev()
// Stop at `Deref`; standard ABI alignment applies there.
.take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref))
// Consider the packed alignments at play here...
.filter_map(|(base, _elem)| {
base.ty(local_decls, tcx).ty.ty_adt_def().and_then(|adt| adt.repr().pack)
})
// ... and compute their minimum.
// The overall smallest alignment is what matters.
.min()
}
40 changes: 40 additions & 0 deletions src/test/ui/issues/issue-99838.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// run-pass
#![feature(bench_black_box)]
use std::hint;

struct U16(u16);

impl Drop for U16 {
fn drop(&mut self) {
// Prevent LLVM from optimizing away our alignment check.
assert!(hint::black_box(self as *mut U16 as usize) % 2 == 0);
}
}

struct HasDrop;

impl Drop for HasDrop {
fn drop(&mut self) {}
}

struct Wrapper {
_a: U16,
b: HasDrop,
}

#[repr(packed)]
struct Misalign(u8, Wrapper);

fn main() {
let m = Misalign(
0,
Wrapper {
_a: U16(10),
b: HasDrop,
},
);
// Put it somewhere definitely even (so the `a` field is definitely at an odd address).
let m: ([u16; 0], Misalign) = ([], m);
// Move out one field, so we run custom per-field drop logic below.
let _x = m.1.1.b;
}
53 changes: 53 additions & 0 deletions src/test/ui/lint/unaligned_references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,57 @@ fn main() {
let _ = &packed2.y; // ok, has align 2 in packed(2) struct
let _ = &packed2.z; // ok, has align 1
}

unsafe {
struct U16(u16);

impl Drop for U16 {
fn drop(&mut self) {
println!("{:p}", self);
}
}

struct HasDrop;

impl Drop for HasDrop {
fn drop(&mut self) {}
}

#[allow(unused)]
struct Wrapper {
a: U16,
b: HasDrop,
}
#[allow(unused)]
#[repr(packed(2))]
struct Wrapper2 {
a: U16,
b: HasDrop,
}

// An outer struct with more restrictive packing than the inner struct -- make sure we
// notice that!
#[repr(packed)]
struct Misalign<T>(u8, T);

let m1 = Misalign(
0,
Wrapper {
a: U16(10),
b: HasDrop,
},
);
let _ref = &m1.1.a; //~ ERROR reference to packed field
//~^ previously accepted

let m2 = Misalign(
0,
Wrapper2 {
a: U16(10),
b: HasDrop,
},
);
let _ref = &m2.1.a; //~ ERROR reference to packed field
//~^ previously accepted
}
}
58 changes: 57 additions & 1 deletion src/test/ui/lint/unaligned_references.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,29 @@ LL | let _ = &packed2.x;
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error: aborting due to 7 previous errors
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:90:20
|
LL | let _ref = &m1.1.a;
| ^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:100:20
|
LL | let _ref = &m2.1.a;
| ^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

error: aborting due to 9 previous errors

Future incompatibility report: Future breakage diagnostic:
error: reference to packed field is unaligned
Expand Down Expand Up @@ -201,3 +223,37 @@ LL | #![deny(unaligned_references)]
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

Future breakage diagnostic:
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:90:20
|
LL | let _ref = &m1.1.a;
| ^^^^^^^
|
note: the lint level is defined here
--> $DIR/unaligned_references.rs:1:9
|
LL | #![deny(unaligned_references)]
| ^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

Future breakage diagnostic:
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:100:20
|
LL | let _ref = &m2.1.a;
| ^^^^^^^
|
note: the lint level is defined here
--> $DIR/unaligned_references.rs:1:9
|
LL | #![deny(unaligned_references)]
| ^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
= help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

0 comments on commit 9097ce9

Please sign in to comment.