fix is_disaligned logic for nested packed structs
This commit is contained in:
parent
bd84c73ffe
commit
9097ce9054
4 changed files with 162 additions and 17 deletions
|
@ -48,20 +48,16 @@ fn is_within_packed<'tcx, L>(
|
||||||
where
|
where
|
||||||
L: HasLocalDecls<'tcx>,
|
L: HasLocalDecls<'tcx>,
|
||||||
{
|
{
|
||||||
for (place_base, elem) in place.iter_projections().rev() {
|
place
|
||||||
match elem {
|
.iter_projections()
|
||||||
// encountered a Deref, which is ABI-aligned
|
.rev()
|
||||||
ProjectionElem::Deref => break,
|
// Stop at `Deref`; standard ABI alignment applies there.
|
||||||
ProjectionElem::Field(..) => {
|
.take_while(|(_base, elem)| !matches!(elem, ProjectionElem::Deref))
|
||||||
let ty = place_base.ty(local_decls, tcx).ty;
|
// Consider the packed alignments at play here...
|
||||||
match ty.kind() {
|
.filter_map(|(base, _elem)| {
|
||||||
ty::Adt(def, _) => return def.repr().pack,
|
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()
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
40
src/test/ui/issues/issue-99838.rs
Normal file
40
src/test/ui/issues/issue-99838.rs
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -47,4 +47,57 @@ fn main() {
|
||||||
let _ = &packed2.y; // ok, has align 2 in packed(2) struct
|
let _ = &packed2.y; // ok, has align 2 in packed(2) struct
|
||||||
let _ = &packed2.z; // ok, has align 1
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
= 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)
|
= 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:
|
Future incompatibility report: Future breakage diagnostic:
|
||||||
error: reference to packed field is unaligned
|
error: reference to packed field is unaligned
|
||||||
|
@ -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)
|
= 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)
|
= 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)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue