Auto merge of #83605 - RalfJung:unaligned, r=petrochenkov
unaligned_references: align(N) fields in packed(N) structs are fine This removes some false positives from the unaligned_references lint: in a `repr(packed(2))` struct, fields of alignment 2 (and less) are guaranteed to be properly aligned, so we do not have to consider them "disaligned".
This commit is contained in:
commit
cc4103089f
7 changed files with 87 additions and 34 deletions
|
@ -1,5 +1,6 @@
|
||||||
use rustc_middle::mir::*;
|
use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
|
use rustc_target::abi::Align;
|
||||||
|
|
||||||
/// Returns `true` if this place is allowed to be less aligned
|
/// Returns `true` if this place is allowed to be less aligned
|
||||||
/// than its containing struct (because it is within a packed
|
/// than its containing struct (because it is within a packed
|
||||||
|
@ -14,17 +15,25 @@ where
|
||||||
L: HasLocalDecls<'tcx>,
|
L: HasLocalDecls<'tcx>,
|
||||||
{
|
{
|
||||||
debug!("is_disaligned({:?})", place);
|
debug!("is_disaligned({:?})", place);
|
||||||
if !is_within_packed(tcx, local_decls, place) {
|
let pack = match is_within_packed(tcx, local_decls, place) {
|
||||||
debug!("is_disaligned({:?}) - not within packed", place);
|
None => {
|
||||||
return false;
|
debug!("is_disaligned({:?}) - not within packed", place);
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
Some(pack) => pack,
|
||||||
|
};
|
||||||
|
|
||||||
let ty = place.ty(local_decls, tcx).ty;
|
let ty = place.ty(local_decls, tcx).ty;
|
||||||
match tcx.layout_raw(param_env.and(ty)) {
|
match tcx.layout_raw(param_env.and(ty)) {
|
||||||
Ok(layout) if layout.align.abi.bytes() == 1 => {
|
Ok(layout) if layout.align.abi <= pack => {
|
||||||
// if the alignment is 1, the type can't be further
|
// If the packed alignment is greater or equal to the field alignment, the type won't be
|
||||||
// disaligned.
|
// further disaligned.
|
||||||
debug!("is_disaligned({:?}) - align = 1", place);
|
debug!(
|
||||||
|
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
|
||||||
|
place,
|
||||||
|
layout.align.abi.bytes(),
|
||||||
|
pack.bytes()
|
||||||
|
);
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -34,7 +43,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_within_packed<'tcx, L>(tcx: TyCtxt<'tcx>, local_decls: &L, place: Place<'tcx>) -> bool
|
fn is_within_packed<'tcx, L>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
local_decls: &L,
|
||||||
|
place: Place<'tcx>,
|
||||||
|
) -> Option<Align>
|
||||||
where
|
where
|
||||||
L: HasLocalDecls<'tcx>,
|
L: HasLocalDecls<'tcx>,
|
||||||
{
|
{
|
||||||
|
@ -45,7 +58,7 @@ where
|
||||||
ProjectionElem::Field(..) => {
|
ProjectionElem::Field(..) => {
|
||||||
let ty = place_base.ty(local_decls, tcx).ty;
|
let ty = place_base.ty(local_decls, tcx).ty;
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
ty::Adt(def, _) if def.repr.packed() => return true,
|
ty::Adt(def, _) => return def.repr.pack,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,5 +66,5 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,13 @@ pub struct Good {
|
||||||
aligned: [u8; 32],
|
aligned: [u8; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(packed(2))]
|
||||||
|
pub struct Packed2 {
|
||||||
|
x: u32,
|
||||||
|
y: u16,
|
||||||
|
z: u8,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] };
|
let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] };
|
||||||
|
@ -32,4 +39,12 @@ fn main() {
|
||||||
let _ = &good.aligned; // ok, has align 1
|
let _ = &good.aligned; // ok, has align 1
|
||||||
let _ = &good.aligned[2]; // ok, has align 1
|
let _ = &good.aligned[2]; // ok, has align 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let packed2 = Packed2 { x: 0, y: 0, z: 0 };
|
||||||
|
let _ = &packed2.x; //~ ERROR reference to packed field
|
||||||
|
//~^ previously accepted
|
||||||
|
let _ = &packed2.y; // ok, has align 2 in packed(2) struct
|
||||||
|
let _ = &packed2.z; // ok, has align 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
error: reference to packed field is unaligned
|
error: reference to packed field is unaligned
|
||||||
--> $DIR/unaligned_references.rs:15:17
|
--> $DIR/unaligned_references.rs:22:17
|
||||||
|
|
|
|
||||||
LL | let _ = &good.ptr;
|
LL | let _ = &good.ptr;
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -14,7 +14,7 @@ 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)
|
||||||
|
|
||||||
error: reference to packed field is unaligned
|
error: reference to packed field is unaligned
|
||||||
--> $DIR/unaligned_references.rs:17:17
|
--> $DIR/unaligned_references.rs:24:17
|
||||||
|
|
|
|
||||||
LL | let _ = &good.data;
|
LL | let _ = &good.data;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
@ -24,7 +24,7 @@ LL | let _ = &good.data;
|
||||||
= 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)
|
||||||
|
|
||||||
error: reference to packed field is unaligned
|
error: reference to packed field is unaligned
|
||||||
--> $DIR/unaligned_references.rs:20:17
|
--> $DIR/unaligned_references.rs:27:17
|
||||||
|
|
|
|
||||||
LL | let _ = &good.data as *const _;
|
LL | let _ = &good.data as *const _;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
@ -34,7 +34,7 @@ LL | let _ = &good.data as *const _;
|
||||||
= 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)
|
||||||
|
|
||||||
error: reference to packed field is unaligned
|
error: reference to packed field is unaligned
|
||||||
--> $DIR/unaligned_references.rs:22:27
|
--> $DIR/unaligned_references.rs:29:27
|
||||||
|
|
|
|
||||||
LL | let _: *const _ = &good.data;
|
LL | let _: *const _ = &good.data;
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
@ -44,7 +44,7 @@ LL | let _: *const _ = &good.data;
|
||||||
= 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)
|
||||||
|
|
||||||
error: reference to packed field is unaligned
|
error: reference to packed field is unaligned
|
||||||
--> $DIR/unaligned_references.rs:25:17
|
--> $DIR/unaligned_references.rs:32:17
|
||||||
|
|
|
|
||||||
LL | let _ = good.data.clone();
|
LL | let _ = good.data.clone();
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -54,7 +54,7 @@ LL | let _ = good.data.clone();
|
||||||
= 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)
|
||||||
|
|
||||||
error: reference to packed field is unaligned
|
error: reference to packed field is unaligned
|
||||||
--> $DIR/unaligned_references.rs:28:17
|
--> $DIR/unaligned_references.rs:35:17
|
||||||
|
|
|
|
||||||
LL | let _ = &good.data2[0];
|
LL | let _ = &good.data2[0];
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
@ -63,5 +63,15 @@ LL | let _ = &good.data2[0];
|
||||||
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
|
= 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)
|
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
|
||||||
|
|
||||||
error: aborting due to 6 previous errors
|
error: reference to packed field is unaligned
|
||||||
|
--> $DIR/unaligned_references.rs:45:17
|
||||||
|
|
|
||||||
|
LL | let _ = &packed2.x;
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= 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)
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
|
|
17
src/test/ui/packed/packed-struct-borrow-element-64bit.rs
Normal file
17
src/test/ui/packed/packed-struct-borrow-element-64bit.rs
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// run-pass (note: this is spec-UB, but it works for now)
|
||||||
|
// ignore-32bit (needs `usize` to be 8-aligned to reproduce all the errors below)
|
||||||
|
#![allow(dead_code)]
|
||||||
|
// ignore-emscripten weird assertion?
|
||||||
|
|
||||||
|
#[repr(C, packed(4))]
|
||||||
|
struct Foo4C {
|
||||||
|
bar: u8,
|
||||||
|
baz: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn main() {
|
||||||
|
let foo = Foo4C { bar: 1, baz: 2 };
|
||||||
|
let brw = &foo.baz; //~WARN reference to packed field is unaligned
|
||||||
|
//~^ previously accepted
|
||||||
|
assert_eq!(*brw, 2);
|
||||||
|
}
|
13
src/test/ui/packed/packed-struct-borrow-element-64bit.stderr
Normal file
13
src/test/ui/packed/packed-struct-borrow-element-64bit.stderr
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
warning: reference to packed field is unaligned
|
||||||
|
--> $DIR/packed-struct-borrow-element-64bit.rs:14:15
|
||||||
|
|
|
||||||
|
LL | let brw = &foo.baz;
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: `#[warn(unaligned_references)]` on by default
|
||||||
|
= 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)
|
||||||
|
|
||||||
|
warning: 1 warning emitted
|
||||||
|
|
|
@ -30,9 +30,4 @@ pub fn main() {
|
||||||
let brw = &foo.baz; //~WARN reference to packed field is unaligned
|
let brw = &foo.baz; //~WARN reference to packed field is unaligned
|
||||||
//~^ previously accepted
|
//~^ previously accepted
|
||||||
assert_eq!(*brw, 2);
|
assert_eq!(*brw, 2);
|
||||||
|
|
||||||
let foo = Foo4C { bar: 1, baz: 2 };
|
|
||||||
let brw = &foo.baz; //~WARN reference to packed field is unaligned
|
|
||||||
//~^ previously accepted
|
|
||||||
assert_eq!(*brw, 2);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,15 +19,5 @@ LL | let brw = &foo.baz;
|
||||||
= note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
|
= 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)
|
= note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
|
||||||
|
|
||||||
warning: reference to packed field is unaligned
|
warning: 2 warnings emitted
|
||||||
--> $DIR/packed-struct-borrow-element.rs:35:15
|
|
||||||
|
|
|
||||||
LL | let brw = &foo.baz;
|
|
||||||
| ^^^^^^^^
|
|
||||||
|
|
|
||||||
= 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)
|
|
||||||
|
|
||||||
warning: 3 warnings emitted
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue