Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tracking Issue for future-incompatibility warning unaligned_references #82523

Closed
RalfJung opened this issue Feb 25, 2021 · 77 comments · Fixed by #102513
Closed

Tracking Issue for future-incompatibility warning unaligned_references #82523

RalfJung opened this issue Feb 25, 2021 · 77 comments · Fixed by #102513
Labels
C-future-incompatibility Category: Future-incompatibility lints C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@RalfJung
Copy link
Member

RalfJung commented Feb 25, 2021

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.

@RalfJung RalfJung added the C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC label Feb 25, 2021
Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue Mar 27, 2021
…ochenkov

make unaligned_references future-incompat lint warn-by-default

and also remove the safe_packed_borrows lint that it replaces.

`std::ptr::addr_of!` has hit beta now and will hit stable in a month, so I propose we start fixing rust-lang#27060 for real: creating a reference to a field of a packed struct needs to eventually become a hard error; this PR makes it a warn-by-default future-incompat lint. (The lint already existed, this just raises its default level.) At the same time I removed the corresponding code from unsafety checking; really there's no reason an `unsafe` block should make any difference here.

For references to packed fields outside `unsafe` blocks, this means `unaligned_refereces` replaces the previous `safe_packed_borrows` warning with a link to rust-lang#82523 (and no more talk about unsafe blocks making any difference). So behavior barely changes, the warning is just worded differently. For references to packed fields inside `unsafe` blocks, this PR shows a new future-incompat warning.

Closes rust-lang#46043 because that lint no longer exists.
stlankes added a commit to stlankes/kernel that referenced this issue Apr 25, 2021
stlankes added a commit to hermit-os/kernel that referenced this issue Apr 25, 2021
rbradford added a commit to rbradford/cloud-hypervisor that referenced this issue May 7, 2021
error: reference to packed field is unaligned
  --> virtio-devices/src/vhost_user/fs.rs:85:21
   |
85 |                     fs.flags[i].bits() as i32,
   |                     ^^^^^^^^^^^
   |
   = note: `-D unaligned-references` implied by `-D warnings`
   = warning: this was previously accepted by the compiler but is being
phased out; it will become a hard error in a future release!
   = note: for more information, see issue #82523
<rust-lang/rust#82523>
   = note: fields of packed structs are not properly aligned, and
creating a misaligned reference is undefined behavior (even if that
reference is never dereferenced)

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
rbradford added a commit to rbradford/cloud-hypervisor that referenced this issue May 7, 2021
error: reference to packed field is unaligned
  --> virtio-devices/src/vhost_user/fs.rs:85:21
   |
85 |                     fs.flags[i].bits() as i32,
   |                     ^^^^^^^^^^^
   |
   = note: `-D unaligned-references` implied by `-D warnings`
   = warning: this was previously accepted by the compiler but is being
phased out; it will become a hard error in a future release!
   = note: for more information, see issue #82523
<rust-lang/rust#82523>
   = note: fields of packed structs are not properly aligned, and
creating a misaligned reference is undefined behavior (even if that
reference is never dereferenced)

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
sboeuf pushed a commit to cloud-hypervisor/cloud-hypervisor that referenced this issue May 7, 2021
error: reference to packed field is unaligned
  --> virtio-devices/src/vhost_user/fs.rs:85:21
   |
85 |                     fs.flags[i].bits() as i32,
   |                     ^^^^^^^^^^^
   |
   = note: `-D unaligned-references` implied by `-D warnings`
   = warning: this was previously accepted by the compiler but is being
phased out; it will become a hard error in a future release!
   = note: for more information, see issue #82523
<rust-lang/rust#82523>
   = note: fields of packed structs are not properly aligned, and
creating a misaligned reference is undefined behavior (even if that
reference is never dereferenced)

Signed-off-by: Rob Bradford <robert.bradford@intel.com>
liuw added a commit to liuw/cloud-hypervisor that referenced this issue Jul 13, 2021
Just like how it is done in the top-level Cargo.toml.

This fixes a warning [0] when building the fuzzer binaries.

[0] rust-lang/rust#82523

Signed-off-by: Wei Liu <liuwe@microsoft.com>
likebreath pushed a commit to cloud-hypervisor/cloud-hypervisor that referenced this issue Jul 13, 2021
Just like how it is done in the top-level Cargo.toml.

This fixes a warning [0] when building the fuzzer binaries.

[0] rust-lang/rust#82523

Signed-off-by: Wei Liu <liuwe@microsoft.com>
slp pushed a commit to rust-vmm/vhost that referenced this issue Jul 29, 2021
fix warning, when compiling with 1.53.0
```
warning: reference to packed field is unaligned
   --> src/vhost_user/message.rs:252:53
    |
252 |   unsafe { std::mem::transmute_copy::<u32, R>(&self.request) }
    |                                               ^^^^^^^^^^^^^
    |
    = note: `#[warn(unaligned_references)]` on by default
    = warning: this was previously accepted by the compiler but is being
      phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523
      <rust-lang/rust#82523>
    = note: fields of packed structs are not properly aligned, and
      creating a misaligned reference is undefined behavior (even if
      that reference is never dereferenced)
```

Signed-off-by: wanglei <wllenyj@linux.alibaba.com>
@golddranks
Copy link
Contributor

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
Copy link
Member Author

RalfJung commented 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.

npmccallum pushed a commit to enarx-archive/sev that referenced this issue Aug 9, 2021
This will be an error some day.

warning: reference to packed field is unaligned
   --> src/certs/sev/cert/mod.rs:176:47
    |
176 |             1 => PublicKey::try_from(unsafe { &value.v1.body.data.key }),
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: `#[warn(unaligned_references)]` on by default
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <rust-lang/rust#82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)

Also bump the minimum stable compiler. The addr_of! macro was introduced in
1.51.0.

Signed-off-by: Connor Kuehl <ckuehl@redhat.com>
ankitbhrdwj added a commit to gz/rust-topology that referenced this issue Aug 19, 2021
simonschoening pushed a commit to simonschoening/libhermit-rs that referenced this issue Aug 26, 2021
@osa1
Copy link
Contributor

osa1 commented Sep 1, 2021

Sorry if this is not the right place for this question, but I'm curious about how to do method calls with &self receivers now when the receiver is potentially unaligned. Examples in the original post do not show this. Example:

#[repr(packed)]
pub struct Obj {
    pub field: String,
}

pub unsafe fn test(concat: *const Obj) {
    println!("{}", (*concat).field.len());
    //             ^^^^^^^^^^^^^^^ "reference to packed field is unaligned"
}

Here a reference is created implicitly for the method call, causing the warning.

Since the method is defined in a library I can't make it a *const self method (with arbitrary_self_types). What is the suggested fix for cases like this?

When I have the control over called methods, do I make the methods take a *const/mut self receiver? Or is there a better way to fix this?

When compiling to platforms with no alignment restrictions (such as Wasm) is there a way to relax this check?

Finally, looking at https://doc.rust-lang.org/reference/behavior-considered-undefined.html (linked in the issue description), it doesn't mention unaligned references. Should it be updated? It also doesn't link to this issue.

@RalfJung
Copy link
Member Author

RalfJung commented Sep 1, 2021

I'm curious about how to do method calls with &self receivers now when the receiver is potentially unaligned

It is not possible (and has never been possible) to call such methods on packed fields. You have to first move the data to some well-aligned place, and then call the method.

Finally, looking at https://doc.rust-lang.org/reference/behavior-considered-undefined.html (linked in the issue description), it doesn't mention unaligned references.

It does, the following is listed as UB due to producing an invalid value: "A reference or Box that is dangling, unaligned, or points to an invalid value."

@osa1
Copy link
Contributor

osa1 commented Sep 1, 2021

It is not possible (and has never been possible) to call such methods on packed fields.

I'm confused by this. My example above does exactly this, and it used to work without warnings a few versions ago. It works today, but generates a warning. Did I misunderstand what you mean? Do you mean it's never supposed to work, rather than it never worked?

emkw added a commit to emkw/rust-p0f_api that referenced this issue Jan 22, 2023
This was previously accepted by the compiler, then it was being phased out,
and finally it became a hard error.
For more information, see Rust issue #82523
rust-lang/rust#82523
@bors bors closed this as completed in 5b6ed25 Feb 1, 2023
RalfJung pushed a commit to RalfJung/miri that referenced this issue Feb 1, 2023
…lot,scottmcm

make unaligned_reference a hard error

The `unaligned_references` lint has been warn-by-default since Rust 1.53 (rust-lang/rust#82525) and deny-by-default with mention in cargo future-incompat reports since Rust 1.62 (rust-lang/rust#95372). Current nightly will become Rust 1.66, so (unless major surprises show up with crater) I think it is time we make this a hard error, and close this old soundness gap in the language.

EDIT: Turns out this will only land for Rust 1.67, so there is another 6 weeks of time here for crates to adjust.

Fixes rust-lang/rust#82523.
dtolnay added a commit to serde-rs/serde that referenced this issue Feb 2, 2023
    warning: lint `unaligned_references` has been removed: converted into hard error, see issue #82523 <rust-lang/rust#82523> for more information
        --> test_suite/tests/test_macros.rs:1931:8
         |
    1931 | #[deny(unaligned_references)]
         |        ^^^^^^^^^^^^^^^^^^^^
         |
         = note: `#[warn(renamed_and_removed_lints)]` on by default
@RalfJung
Copy link
Member Author

RalfJung commented Feb 4, 2023

It's been 7.5 years since #27060 was reported, but the problem is finally fixed for good. :)

spearman added a commit to spearman/enet-sys that referenced this issue Apr 17, 2023
This fixes the warning:

warning: lint `unaligned_references` has been removed: converted into
hard error, see issue #82523
<rust-lang/rust#82523> for more information
justxuewei added a commit to justxuewei/dragonball-sandbox that referenced this issue Apr 24, 2023
Obtaining reference of unaligned fields is being phased out. Therefore,
`&struct.field` is replaced with `std::ptr::addr_of!(struct.field)` to
avoid those warning issues. For more details, please refer to
rust-lang/rust#82523.

Fixes: openanolis#273

Signed-off-by: Xuewei Niu <niuxuewei.nxw@antgroup.com>
studychao pushed a commit to openanolis/dragonball-sandbox that referenced this issue Apr 24, 2023
Obtaining reference of unaligned fields is being phased out. Therefore,
`&struct.field` is replaced with `std::ptr::addr_of!(struct.field)` to
avoid those warning issues. For more details, please refer to
rust-lang/rust#82523.

Fixes: #273

Signed-off-by: Xuewei Niu <niuxuewei.nxw@antgroup.com>
@jrose-signal
Copy link

I ran into #110777 today, but now I'm wondering why you can't form a reference to a field x in a repr(packed) struct where the type of x is itself repr(packed). That would allow my use of Debug to continue working.

@mathstuf
Copy link
Contributor

Because x may be misaligned within the parent struct for its own alignment rules (which are not affected by repr(packed) AFAIK). I think here you'd want something like #[allow_unaligned] on the type of x so that nothing can assume anything about the alignment of the type.

@jrose-signal
Copy link

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 had derive(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
Copy link
Member Author

RalfJung commented Apr 24, 2023

I ran into #110777 today, but now I'm wondering why you can't form a reference to a field x in a repr(packed) struct where the type of x is itself repr(packed).

You can:

pub(crate) struct UInt16LE {
    bytes: [u8; 2],
}

#[repr(C, packed)] // struct has the same layout without the `packed`!
pub(crate) struct Header {
    version: u8,
    kind: UInt16LE,
}

const _: () = {
    assert!(std::mem::align_of::<Header>() == 1);
};

fn main() {
    let h = Header { version: 0, kind: UInt16LE { bytes: [0, 0] }};
    let r = &h.kind; // taking the reference
}

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 the packed does not change the layout in any way, which was deemed acceptable breakage. Sorry that it hit you!

@jrose-signal
Copy link

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
Copy link
Member

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.

@apiraino apiraino removed the I-prioritize Issue: Indicates that prioritization has been requested for this issue. label May 16, 2023
studychao pushed a commit to studychao/dragonball-sandbox that referenced this issue Jul 7, 2023
Obtaining reference of unaligned fields is being phased out. Therefore,
`&struct.field` is replaced with `std::ptr::addr_of!(struct.field)` to
avoid those warning issues. For more details, please refer to
rust-lang/rust#82523.

Fixes: openanolis#273

Signed-off-by: Xuewei Niu <niuxuewei.nxw@antgroup.com>
AminoffZ added a commit to AminoffZ/nonogrid that referenced this issue Aug 25, 2023
lint `unaligned_references` has been removed: converted into hard error, see issue #82523 <rust-lang/rust#82523> for more information
@dtolnay dtolnay removed the S-tracking-needs-to-bake Status: The implementation is "complete" but it needs time to bake. label Apr 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-future-incompatibility Category: Future-incompatibility lints C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.