Skip to content

Tracking Issue for future-incompatibility warning unaligned_references #82523

Closed

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 unaligned

The 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});

For further background, see #46043, #27060.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    C-future-incompatibilityCategory: Future-incompatibility lintsC-tracking-issueCategory: A tracking issue for an RFC or an unstable feature.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-langRelevant to the language team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions