blob: 2722dac104b7f94c9b12191fa50c90af53b01169 [file] [log] [blame] [view]
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