Skip to content

invalid_reference_casting lint catches some patterns that aren't UB #116410

@LegionMammal978

Description

@LegionMammal978

When reading the 1.73.0 release notes, I noticed that the invalid_reference_casting lint was made deny-by-default in #112431, under the premise that casting &T to &mut T via raw pointers is always UB under Stacked Borrows. However, the lint appears a bit overly strict, since such a cast does not cause UB when T is a zero-sized type:

#![allow(invalid_reference_casting)]

fn main() {
    let r1: &() = &();
    let r2: &mut () = unsafe { &mut *(r1 as *const _ as *mut _) };
    *r2 = ();
}

Without #![allow(invalid_reference_casting)], this cast triggers the lint in 1.75.0-nightly (187b813 2023-10-03):

error: casting `&T` to `&mut T` is undefined behavior, even if the reference is unused, consider instead using an `UnsafeCell`
 --> src/main.rs:5:32
  |
5 |     let r2: &mut () = unsafe { &mut *(r1 as *const _ as *mut _) };
  |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: for more information, visit <https://doc.rust-lang.org/book/ch15-05-interior-mutability.html>
  = note: `#[deny(invalid_reference_casting)]` on by default

However, when the lint is disabled, Miri runs the program successfully, under both Stacked Borrows and Tree Borrows. This makes sense looking at the rules: the reference doesn't point to any bytes, so it doesn't need to perform any access or be granted any permissions.

This pattern looks a bit dubious when expressed as a reference cast, but it is not UB. Therefore, I would suggest downgrading or turning off the lint when the destination type is a ZST.

Note: An earlier version of this issue also considered directly casting from &UnsafeCell<i32> to &mut i32, which is legal under Stacked Borrows and Tree Borrows, but explicitly called out as UB in the UnsafeCell documentation. It was decided that linting on this case, as well as the related case of casting from &UnsafeCell<i32> to &mut UnsafeCell<i32> which isn't explicitly mentioned, is permissible as an enforcement of library UB until the aliasing rules are ultimately finalized. This was clarified in the diagnostic by #116421.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-lintsArea: Lints (warnings about flaws in source code) such as unused_mut.C-bugCategory: This is a bug.L-invalid_reference_castingLint: invalid_reference_castingT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-opsemRelevant to the opsem team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions