| 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: | |
| ```compile_fail,E0793 | |
| #[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. | |
| ``` | |
| #[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. | |
| ```compile_fail,E0793 | |
| #[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. | |
| [packed]: https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers | |
| [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html | |
| [issue #82523]: https://github.com/rust-lang/rust/issues/82523 |