Error code E0793
An unaligned reference to a field of a packed struct
or union
was created.
The #[repr(packed)]
attribute removes padding between fields, which can
cause fields to be stored at unaligned memory addresses. Creating references
to such fields violates Rust's memory safety guarantees and can lead to
undefined behavior in optimized code.
Erroneous code example:
#![allow(unused)] fn main() { #[repr(packed)] pub struct Foo { field1: u64, field2: u8, } unsafe { let foo = Foo { field1: 0, field2: 0 }; // Accessing the field directly is fine. let val = foo.field1; // A reference to a packed field causes a error. let val = &foo.field1; // ERROR // An implicit `&` is added in format strings, causing the same error. println!("{}", foo.field1); // ERROR } }
Creating a reference to an insufficiently aligned packed field is
undefined behavior and therefore disallowed. Using an unsafe
block does not
change anything about this. Instead, the code should do a copy of the data in
the packed field or use raw pointers and unaligned accesses.
#![allow(unused)] fn main() { #[repr(packed)] pub struct Foo { field1: u64, field2: u8, } unsafe { let foo = Foo { field1: 0, field2: 0 }; // Instead of a reference, we can create a raw pointer... let ptr = std::ptr::addr_of!(foo.field1); // ... and then (crucially!) access it in an explicitly unaligned way. let val = unsafe { ptr.read_unaligned() }; // This would *NOT* be correct: // let val = unsafe { *ptr }; // Undefined Behavior due to unaligned load! // For formatting, we can create a copy to avoid the direct reference. let copy = foo.field1; println!("{}", copy); // Creating a copy can be written in a single line with curly braces. // (This is equivalent to the two lines above.) println!("{}", { foo.field1 }); // A reference to a field that will always be sufficiently aligned is safe: println!("{}", foo.field2); } }
Unions
Although creating a reference to a union
field is unsafe
, this error
will still be triggered if the referenced field is not sufficiently
aligned. Use addr_of!
and raw pointers in the same way as for struct fields.
#![allow(unused)] fn main() { #[repr(packed)] pub union Foo { field1: u64, field2: u8, } unsafe { let foo = Foo { field1: 0 }; // Accessing the field directly is fine. let val = foo.field1; // A reference to a packed union field causes an error. let val = &foo.field1; // ERROR } }
Additional information
Note that this error is specifically about references to packed fields. Direct by-value access of those fields is fine, since then the compiler has enough information to generate the correct kind of access.
See issue #82523 for more information.