Skip to content

core::ptr::replace implementation is unsound since Rust 1.80 #138351

Open
@orlp

Description

@orlp

Consider the following program:

fn main() {
    use core::ptr::*;
    unsafe { dbg!(replace(null_mut(), ())); }
}

This was made a legal program in Rust 1.80, the preconditions state:

  • dst must be valid for both reads and writes.
  • dst must be properly aligned.
  • dst must point to a properly initialized value of type T.

This is because in Rust 1.80 the following line was added to valid:

For operations of size zero, every pointer is valid, including the null pointer. The following points are only concerned with non-zero-sized accesses.

Nevertheless, running the above program results in undefined behavior:

error: Undefined Behavior: constructing invalid value: encountered a null reference
    --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1227:22
     |
1227 |         mem::replace(&mut *dst, src)
     |                      ^^^^^^^^^ constructing invalid value: encountered a null reference
     |
     = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
     = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
     = note: BACKTRACE:
     = note: inside `std::ptr::replace::<()>` at /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/mod.rs:1227:22: 1227:31
note: inside `main`
    --> src/main.rs:3:19
     |
3    |     unsafe { dbg!(replace(null_mut(), ())); }
     |                   ^^^^^^^^^^^^^^^^^^^^^^^

Rather than changing the implementation of core::ptr::replace, or an isolated change to the requirements of core::ptr::replace, I would like to see the change to the definition of a valid pointer for ZSTs reverted, I've expanded more about my thoughts and provided more arguments in this T-opsem zulip thread. In short, I believe that unsoundness similar to the case here in core::ptr::replace will keep happening as long as "dereferencing a pointer" and "reborrowing a pointer" have different requirements (which they do since Rust 1.80).

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.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.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