Skip to content

ptr-as-ptr confused by ptr::addr_of_mut! macro #15232

Open
@matthiaskrgr

Description

@matthiaskrgr

Using the following flags

--force-warn clippy::ptr-as-ptr

this code:

//! Tests specific for <https://github.com/rust-lang/rust/issues/117945>: zero-sized operations.

use std::ptr;

fn main() {
    // Null.
    test_ptr(ptr::null_mut::<()>());
    // No provenance.
    test_ptr(ptr::without_provenance_mut::<()>(1));
    // Out-of-bounds.
    let mut b = Box::new(0i32);
    let ptr = ptr::addr_of_mut!(*b) as *mut ();
    test_ptr(ptr.wrapping_byte_add(2));
    // Dangling (use-after-free).
    drop(b);
    test_ptr(ptr);
}

fn test_ptr(ptr: *mut ()) {
    unsafe {
        // Reads and writes.
        let mut val = *ptr;
        *ptr = val;
        ptr.read();
        ptr.write(());
        // Memory access intrinsics.
        // - memcpy (1st and 2nd argument)
        ptr.copy_from_nonoverlapping(&(), 1);
        ptr.copy_to_nonoverlapping(&mut val, 1);
        // - memmove (1st and 2nd argument)
        ptr.copy_from(&(), 1);
        ptr.copy_to(&mut val, 1);
        // - memset
        ptr.write_bytes(0u8, 1);
        // Offset.
        let _ = ptr.offset(0);
        let _ = ptr.offset(1); // this is still 0 bytes
        // Distance.
        let ptr = ptr.cast::<i32>();
        ptr.offset_from(ptr);
        // Distance from other "bad" pointers that have the same address, but different provenance. Some
        // of this is library UB, but we don't want it to be language UB since that would violate
        // provenance monotonicity: if we allow computing the distance between two ptrs with no
        // provenance, we have to allow computing it between two ptrs with arbitrary provenance.
        // - Distance from "no provenance"
        ptr.offset_from(ptr::without_provenance_mut(ptr.addr()));
        // - Distance from out-of-bounds pointer
        let mut b = Box::new(0i32);
        let other_ptr = ptr::addr_of_mut!(*b);
        ptr.offset_from(other_ptr.with_addr(ptr.addr()));
        // - Distance from use-after-free pointer
        drop(b);
        ptr.offset_from(other_ptr.with_addr(ptr.addr()));
    }
}

caused the following diagnostics:

    Blocking waiting for file lock on package cache
    Blocking waiting for file lock on package cache
    Blocking waiting for file lock on package cache
    Blocking waiting for file lock on package cache
    Checking _zero-sized-accesses-and-offsets v0.1.0 (/run/user/1085/tmp/dir.tp0UQIUgLzNJ/icemaker_clippyfix_tempdir.8nE15X1manAi/_zero-sized-accesses-and-offsets)
warning: `as` casting between raw pointers without changing their constness
  --> src/main.rs:12:15
   |
12 |     let ptr = ptr::addr_of_mut!(*b) as *mut ();
   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast`, a safer alternative: `(&raw mut $place).cast::<()>()`
   |
   = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#ptr_as_ptr
   = note: requested on the command line with `--force-warn clippy::ptr-as-ptr`

warning: `_zero-sized-accesses-and-offsets` (bin "_zero-sized-accesses-and-offsets") generated 1 warning
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.18s

However after applying these diagnostics, the resulting code:

//! Tests specific for <https://github.com/rust-lang/rust/issues/117945>: zero-sized operations.

use std::ptr;

fn main() {
    // Null.
    test_ptr(ptr::null_mut::<()>());
    // No provenance.
    test_ptr(ptr::without_provenance_mut::<()>(1));
    // Out-of-bounds.
    let mut b = Box::new(0i32);
    let ptr = (&raw mut $place).cast::<()>();
    test_ptr(ptr.wrapping_byte_add(2));
    // Dangling (use-after-free).
    drop(b);
    test_ptr(ptr);
}

fn test_ptr(ptr: *mut ()) {
    unsafe {
        // Reads and writes.
        let mut val = *ptr;
        *ptr = val;
        ptr.read();
        ptr.write(());
        // Memory access intrinsics.
        // - memcpy (1st and 2nd argument)
        ptr.copy_from_nonoverlapping(&(), 1);
        ptr.copy_to_nonoverlapping(&mut val, 1);
        // - memmove (1st and 2nd argument)
        ptr.copy_from(&(), 1);
        ptr.copy_to(&mut val, 1);
        // - memset
        ptr.write_bytes(0u8, 1);
        // Offset.
        let _ = ptr.offset(0);
        let _ = ptr.offset(1); // this is still 0 bytes
        // Distance.
        let ptr = ptr.cast::<i32>();
        ptr.offset_from(ptr);
        // Distance from other "bad" pointers that have the same address, but different provenance. Some
        // of this is library UB, but we don't want it to be language UB since that would violate
        // provenance monotonicity: if we allow computing the distance between two ptrs with no
        // provenance, we have to allow computing it between two ptrs with arbitrary provenance.
        // - Distance from "no provenance"
        ptr.offset_from(ptr::without_provenance_mut(ptr.addr()));
        // - Distance from out-of-bounds pointer
        let mut b = Box::new(0i32);
        let other_ptr = ptr::addr_of_mut!(*b);
        ptr.offset_from(other_ptr.with_addr(ptr.addr()));
        // - Distance from use-after-free pointer
        drop(b);
        ptr.offset_from(other_ptr.with_addr(ptr.addr()));
    }
}

no longer compiled:

    Checking _zero-sized-accesses-and-offsets v0.1.0 (/run/user/1085/tmp/dir.tp0UQIUgLzNJ/icemaker_clippyfix_tempdir.8nE15X1manAi/_zero-sized-accesses-and-offsets)
error: expected expression, found `$`
  --> src/main.rs:12:25
   |
12 |     let ptr = (&raw mut $place).cast::<()>();
   |                         ^ expected expression

error: could not compile `_zero-sized-accesses-and-offsets` (bin "_zero-sized-accesses-and-offsets") due to 1 previous error
warning: build failed, waiting for other jobs to finish...
error: could not compile `_zero-sized-accesses-and-offsets` (bin "_zero-sized-accesses-and-offsets" test) due to 1 previous error

Version:

rustc 1.90.0-nightly (f838cbc06 2025-07-08)
binary: rustc
commit-hash: f838cbc06de60819faff3413f374706b74824ca2
commit-date: 2025-07-08
host: x86_64-unknown-linux-gnu
release: 1.90.0-nightly
LLVM version: 20.1.7

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: Clippy is not doing the correct thingI-suggestion-causes-bugIssue: The suggestion compiles but changes the code to behave in an unintended wayT-macrosType: Issues with macros and macro expansion

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions