Skip to content

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

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).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.I-lang-radarItems that are on lang's radar and will need eventual work or consideration.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-langRelevant to the language teamT-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