Skip to content

&raw const some_union.field erroneously requires unsafe #141264

@kupiakos

Description

@kupiakos
Contributor

I tried this code:

#[repr(C)]
union Foo {
    x: u8,
    y: u32,
}

impl Foo {
    fn zero_first_byte(&mut self) {
        let p = &raw mut self.x;
        unsafe { *p = 0 }
    }
}

I expected to see this happen: &raw mut self.x should be a safe operation, because it consists only of in-bounds pointer arithmetic and does not construct a reference or value to uninit. An equivalent using offset_of! is safe:

// wrapping_add is used because the compiler's knowledge of the field offset being in-bounds is lost.
let p: *mut u8 = ptr::from_mut(self).wrapping_byte_add(mem::offset_of!(Self, x)).cast();

Instead, this happened:

error[E0133]: access to union field is unsafe and requires unsafe block
  --> src/lib.rs:12:26
   |
12 |         let p = &raw mut self.x;
   |                          ^^^^^^ access to union field
   |
   = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior

This indicates that Rust is blanket-banning access to the place self.x without consideration for how that place is used. This seems to be an oversight in adding ptr::addr_of! and the &raw operation. It is unsafe to construct a reference or move from such a place, but it should be safe to spell the place and get a raw pointer to it.

This should instead act more like access to packed fields: spelling packed_val.unaligned_field only errors when constructing a reference to that field - merely spelling the place, moving, or using &raw const packed_val.unaligned_field is accepted in safe code.

Meta

rustc --version --verbose:

rustc 1.87.0 (17067e9ac 2025-05-09)
binary: rustc
commit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359
commit-date: 2025-05-09
host: x86_64-unknown-linux-gnu
release: 1.87.0
LLVM version: 20.1.1

Occurs on current stable, beta, and nightly (2025-05-18 4d051fb306e661654d08).
No backtrace was emitted.

Activity

added
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on May 19, 2025
kupiakos

kupiakos commented on May 19, 2025

@kupiakos
ContributorAuthor

For reference, according to Miri (on the playground), the &raw operation is not considered a read:

fn main() {
    let mut foo = Foo { y: MaybeUninit::uninit() };
    let p = unsafe { &raw mut foo.x };
    // No UB reported by Miri - constructing the raw pointer is not a read.
    // Writing is fine.
    unsafe { *p = 10 };

    // Reading requires the field is init first.
    println!("{}", unsafe { *p });
}
Veykril

Veykril commented on May 20, 2025

@Veykril
Member

There is an old zulip discussion regarding this #t-opsem > `&raw const/mut union.field`

added
C-discussionCategory: Discussion or questions that doesn't represent real issues.
T-opsemRelevant to the opsem team
and removed
C-bugCategory: This is a bug.
on May 20, 2025
added
T-langRelevant to the language team
and removed
needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.
on May 23, 2025
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-discussionCategory: Discussion or questions that doesn't represent real issues.T-langRelevant to the language teamT-opsemRelevant to the opsem team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @kupiakos@Veykril@lolbinarycat@rustbot@Noratrieb

      Issue actions

        `&raw const some_union.field` erroneously requires `unsafe` · Issue #141264 · rust-lang/rust