rust-lang / rust-lang/reference

[undefined.validity.undef] paragraph contradicts miri and UCG?

Open
#2,009 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-undefined-behavior
Dominant language
Rust
Stars
1.6k
Forks
607
PR merge metrics
PR metrics pending

Description

Note: Uninitialized memory is also implicitly invalid for any type that has a restricted set of valid values. In other words, the only cases in which reading uninitialized memory is permitted are inside unions and in “padding” (the gaps between the fields of a type).

miri rejects reading from the unitialized part of a union:

use std::mem::MaybeUninit;

union U {
    _f1: f32,
    _f2: (),
}

fn main() {
    let u: U = unsafe { MaybeUninit::uninit().assume_init() };
    eprintln!("{:?}", unsafe { u._f1 });
}
error: Undefined Behavior: reading memory at alloc165[0x0..0x4], but memory is uninitialized at [0x0..0x4], and this operation requires initialized memory
  --> src/main.rs:10:32
   |
10 |     eprintln!("{:?}", unsafe { u._f1 });
   |                                ^^^^^ Undefined Behavior occurred here
   |
   = 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 `main` at src/main.rs:10:32: 10:37

Uninitialized memory occurred at alloc165[0x0..0x4], in this allocation:
alloc165 (stack variable, size: 4, align: 4) {
    __ __ __ __                                     │ ░░░░
}

playground

And it also rejects reading from uninitialized padding bytes:

#[repr(C)]
struct S {
    a: u16,
    b: u32,
}

fn main() {
    let s = S {
        a: u16::MAX,
        b: u32::MAX,
    };
    let byte_slice = unsafe {
        std::slice::from_raw_parts((&s as *const S) as *const u8, std::mem::size_of::<S>())
    };
    eprintln!("{:x?}", byte_slice);
}
ff, ff, error: Undefined Behavior: reading memory at alloc165[0x2..0x3], but memory is uninitialized at [0x2..0x3], and this operation requires initialized memory
  --> /playground/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/fmt/num.rs:73:1
   |
73 | radix_integers! { i8, u8 }
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
   |
   = 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 `main`
  --> src/main.rs:15:5
   |
15 |     eprintln!("{:x?}", byte_slice);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: this error originates in the macro `radix_integer` which comes from the expansion of the macro `eprintln` (in Nightly builds, run with -Z macro-backtrace for more info)

Uninitialized memory occurred at alloc165[0x2..0x3], in this allocation:
alloc165 (stack variable, size: 8, align: 4) {
    ff ff __ __ ff ff ff ff                         │ ..░░....
}

Miri's behavior is consistent with this discussion in UCG: https://github.com/rust-lang/unsafe-code-guidelines/issues/395

And consistent with the glossary, afaict: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/reference/src/glossary.md#padding

Should the reference be updated? I possibly misunderstood the paragraph, in which case it should probably be updated anyway.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the quoted paragraph in the Rust Reference, then compare its wording with the linked UCG issue 395 and the glossary's padding entry. Review the supplied Miri examples as evidence for the discrepancy. Done means determining the intended rule and updating the reference text so it agrees with the established guidance.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
documentation
Issue type
Documentation
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.