Skip to content

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

@fasterthanlime

Description

@fasterthanlime

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: rust-lang/unsafe-code-guidelines#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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions