Repository navigation
Tracking Issue for future-incompatibility warning unaligned_references #82523
Description
This is a tracking issue for the future-incompatibility warning unaligned_references.
This warning will fire for code like the following:
#[repr(packed)]
struct Foo1 {
bar: u8,
baz: usize
}
let foo = Foo1 { bar: 1, baz: 2 };
// Direct field accesses are fine.
let val = foo.baz;
// However, creating a reference is not.
let brw = &foo.baz; //~WARN reference to packed field is unaligned
// Format strings implicitly create references.
println!("{}", foo.baz); //~WARN reference to packed field is unalignedThe reason this pattern is being phased out is that Rust requires references to always be aligned; creating an unaligned reference falls under the "creating an invalid value" clause in the Rust definition of Undefined Behavior. Fields of packed structs are not necessarily properly aligned. Hence creating a reference to a field of a packed struct can cause UB, even if it is never used, and even inside an unsafe block. This is a soundness bug, which is fixed by deprecating and eventually disallowing this pattern.
Previously, a future-incompatibility warning was emitted when creating references to packed fields outside an unsafe block; however, that warning was incorrectly silenced inside unsafe blocks.
To fix this code, it needs to stop creating a reference to a packed field. The alternative is to either just copy the packed field by adding curly braces (the compiler knows how to do that despite lack of alignment), or to create a raw pointer:
let mut foo = Foo1 { bar: 1, baz: 2 };
let brw = std::ptr::addr_of!(foo.baz); // Create an immutable raw pointer to the packed field.
let val = unsafe { brw.read_unaligned() }; // Perform an unaligned read of that pointer.
let brw_mut = std::ptr::addr_of_mut!(foo.baz); // Create a mutable raw pointer to the packed field.
unsafe { brw_mut.write_unaligned(val+1); } // Perform an unaligned write to that pointer.
// For formatting, adding curly braces means that a copy of the field is made, stored
// in a (properly aligned) temporary, and a reference to that temporary is being formatted.
println!("{}", {foo.baz});
// This is equivalent to the more verbose
println!("{}", {let copy = foo.baz; copy});
Activity
Rollup merge of rust-lang#82525 - RalfJung:unaligned-ref-warn, r=petr…
minor changes to avoid issue 82523
minor changes to avoid issue 82523
virtio-devices: vhost_user: fs: Don't reference packed struct
fuzz: patch versionize_derive in Cargo.toml
fuzz: patch versionize_derive in Cargo.toml
fix warning: unaligned_references
golddranks commentedon Aug 2, 2021
Should this be deny-by-default for the 2021 edition, or is it too early for this list (and too late for the edition)?
RalfJung commentedon Aug 2, 2021
IIRC the consensus was that since this problem affects all editions, it would not make sense to make it deny-by-default in only in some editions.
Don't reference unaligned packed field
Properly read the unaligned variables in a struct.
minor changes to avoid issue 82523
101 remaining items
RalfJung commentedon Feb 4, 2023
It's been 7.5 years since #27060 was reported, but the problem is finally fixed for good. :)
remove allow unaligned_references, converted to hard error
dbs-utils: Fix clippy issues caused by rust 1.68.2
dbs-utils: Fix clippy issues caused by rust 1.68.2
jrose-signal commentedon Apr 24, 2023
I ran into #110777 today, but now I'm wondering why you can't form a reference to a field
xin arepr(packed)struct where the type ofxis itselfrepr(packed). That would allow my use of Debug to continue working.mathstuf commentedon Apr 24, 2023
Because
xmay be misaligned within the parent struct for its own alignment rules (which are not affected byrepr(packed)AFAIK). I think here you'd want something like#[allow_unaligned]on the type ofxso that nothing can assume anything about the alignment of the type.jrose-signal commentedon Apr 24, 2023
Oh, I forgot that
repr(packed)can take an argument. And proposing that it's allowed for structs that happen to have an alignment of 1 is too broad (since that may not be intended to be a part of the public interface of a struct). But it seems like if a struct explicitly has alignment 1 it could be allowed. (Again, I would not care about this so much except that we hadderive(Debug)on a packed struct with nested packed structs, and they don't technically need to be Copy-ed to be printed because they all have alignment 1.)RalfJung commentedon Apr 24, 2023
You can:
Your issue is that
derive(Debug)has to guess whether it should make a copy or take a reference, without having any type information. (derive macros run before type names are resolved.) For packed structs it guesses making a copy, and that's why you see an error. The only code where this used to work and now errors is code where thepackeddoes not change the layout in any way, which was deemed acceptable breakage. Sorry that it hit you!jrose-signal commentedon Apr 24, 2023
That makes sense. For some reason I was hoping there was some kind of autoref trick involved rather than the derive-macro simply making a choice, but it makes sense that it does not do this. Sorry for the noise, then! (And thanks everyone for the help in both places.)
scottmcm commentedon Apr 24, 2023
The derive macro can't know whether the field types are 1-aligned or packed, so it does the common thing. If you need something else, you'll have to write out the impl yourself.
dbs-utils: Fix clippy issues caused by rust 1.68.2
❌ Remove unaligned_references
fix(pkcs11): avoid unaligned reads of packed CK_ATTRIBUTE fields in t…