Skip to content

unsafe_op_in_unsafe_fn not triggered for raw pointer dereferencing inside addr_of/addr_of_mut #112504

Open
@nhusung

Description

@nhusung

Code

#![forbid(unsafe_op_in_unsafe_fn)]

use core::ptr::addr_of;
use core::ptr::addr_of_mut;

pub struct Foo {
    field: u8
}

pub unsafe fn foo(ptr: *const Foo) -> *const u8 {
    addr_of!((*ptr).field)
}

pub unsafe fn foo_mut(ptr: *mut Foo) -> *mut u8 {
    addr_of_mut!((*ptr).field)
}

Current output

<No error>

Desired output

error[E0133]: dereference of raw pointer is unsafe and requires unsafe block
  --> src/lib.rs:11:5
   |
11 |     addr_of!((*ptr).field)
   |     ^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
   |
   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
   = note: this error originates in the macro `addr_of` (in Nightly builds, run with -Z macro-backtrace for more info)
note: the lint level is defined here
  --> src/lib.rs:1:11
   |
1  | #![forbid(unsafe_op_in_unsafe_fn)]
   |           ^^^^^^^^^^^^^^^^^^^^^^

error[E0133]: dereference of raw pointer is unsafe and requires unsafe block
  --> src/lib.rs:15:5
   |
15 |     addr_of_mut!((*ptr).field)
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer
   |
   = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
   = note: this error originates in the macro `addr_of_mut` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0133`.

Rationale and extra context

When removing the unsafe keywords in the function declarations of the sample code, the compiler emits the errors found in the “desired output” box (except for the note on the unsafe_op_in_unsafe_fn lint). Hence, I was expecting the operations to be unsafe.1 However, with forbid(unsafe_op_in_unsafe_fn) and the functions marked unsafe, no errors are emitted at all.

Other cases

No response

Anything else?

Note that the unsafe_op_in_unsafe_fn lint is not entirely broken for the expr of addr_of!(expr). The following snippet emits an error for calling an unsafe function (but not for dereferencing the raw pointer):

#![forbid(unsafe_op_in_unsafe_fn)]

pub struct Foo {
    field: u8
}

unsafe fn unsafe_id<T>(x: T) -> T { x }

pub unsafe fn foo(ptr: *const Foo) -> *const u8 {
    core::ptr::addr_of!((*unsafe_id(ptr)).field)
}

Playground


Note furthermore that inlining the addr_of!()/addr_of_mut!() macros (using #![feature(raw_ref_op)]) result in the expected behavior:

#![feature(raw_ref_op)]
#![forbid(unsafe_op_in_unsafe_fn)]

pub struct Foo {
    field: u8
}

pub unsafe fn foo(ptr: *const Foo) -> *const u8 {
    &raw const (*ptr).field
}

pub unsafe fn foo_mut(ptr: *mut Foo) -> *mut u8 {
    &raw mut (*ptr).field
}

Playground

Footnotes

  1. I’m not a hundred percent sure about this point as we effectively perform pointer arithmetic only. Conceptually, I would like to understand addr_of!((*ptr).field) as not actually dereferencing ptr. But the docs explicitly state that “the expr in addr_of!(expr) is still subject to all the usual rules. In particular, addr_of!(*ptr::null()) is Undefined Behavior because it dereferences a null pointer.”

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler 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