Skip to content

Commit

Permalink
unaligned_references: align(N) fields in packed(N) structs are fine
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Mar 28, 2021
1 parent 5208f63 commit ee1caae
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 18 deletions.
35 changes: 24 additions & 11 deletions compiler/rustc_mir/src/util/alignment.rs
@@ -1,5 +1,6 @@
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
use rustc_target::abi::Align;

/// Returns `true` if this place is allowed to be less aligned
/// than its containing struct (because it is within a packed
Expand All @@ -14,17 +15,25 @@ where
L: HasLocalDecls<'tcx>,
{
debug!("is_disaligned({:?})", place);
if !is_within_packed(tcx, local_decls, place) {
debug!("is_disaligned({:?}) - not within packed", place);
return false;
}
let pack = match is_within_packed(tcx, local_decls, place) {
None => {
debug!("is_disaligned({:?}) - not within packed", place);
return false;
}
Some(pack) => pack,
};

let ty = place.ty(local_decls, tcx).ty;
match tcx.layout_raw(param_env.and(ty)) {
Ok(layout) if layout.align.abi.bytes() == 1 => {
// if the alignment is 1, the type can't be further
// disaligned.
debug!("is_disaligned({:?}) - align = 1", place);
Ok(layout) if layout.align.abi <= pack => {
// If the packed alignment is greater or equal to the field alignment, the type won't be
// further disaligned.
debug!(
"is_disaligned({:?}) - align = {}, packed = {}; not disaligned",
place,
layout.align.abi.bytes(),
pack.bytes()
);
false
}
_ => {
Expand All @@ -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
L: HasLocalDecls<'tcx>,
{
Expand All @@ -45,13 +58,13 @@ where
ProjectionElem::Field(..) => {
let ty = place_base.ty(local_decls, tcx).ty;
match ty.kind() {
ty::Adt(def, _) if def.repr.packed() => return true,
ty::Adt(def, _) => return def.repr.pack,
_ => {}
}
}
_ => {}
}
}

false
None
}
15 changes: 15 additions & 0 deletions src/test/ui/lint/unaligned_references.rs
Expand Up @@ -8,6 +8,13 @@ pub struct Good {
aligned: [u8; 32],
}

#[repr(packed(2))]
pub struct Packed2 {
x: u32,
y: u16,
z: u8,
}

fn main() {
unsafe {
let good = Good { data: 0, ptr: &0, data2: [0, 0], aligned: [0; 32] };
Expand All @@ -32,4 +39,12 @@ fn main() {
let _ = &good.aligned; // 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
}
}
24 changes: 17 additions & 7 deletions src/test/ui/lint/unaligned_references.stderr
@@ -1,5 +1,5 @@
error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:15:17
--> $DIR/unaligned_references.rs:22:17
|
LL | let _ = &good.ptr;
| ^^^^^^^^^
Expand All @@ -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)

error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:17:17
--> $DIR/unaligned_references.rs:24:17
|
LL | let _ = &good.data;
| ^^^^^^^^^^
Expand All @@ -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)

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 _;
| ^^^^^^^^^^
Expand All @@ -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)

error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:22:27
--> $DIR/unaligned_references.rs:29:27
|
LL | let _: *const _ = &good.data;
| ^^^^^^^^^^
Expand All @@ -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)

error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:25:17
--> $DIR/unaligned_references.rs:32:17
|
LL | let _ = good.data.clone();
| ^^^^^^^^^
Expand All @@ -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)

error: reference to packed field is unaligned
--> $DIR/unaligned_references.rs:28:17
--> $DIR/unaligned_references.rs:35:17
|
LL | let _ = &good.data2[0];
| ^^^^^^^^^^^^^^
Expand All @@ -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: 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

0 comments on commit ee1caae

Please sign in to comment.