Skip to content

&raw const some_union.field erroneously requires unsafe #141264

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kupiakos opened this issue May 19, 2025 · 2 comments · May be fixed by #141469
Open

&raw const some_union.field erroneously requires unsafe #141264

kupiakos opened this issue May 19, 2025 · 2 comments · May be fixed by #141469
Labels
C-discussion Category: Discussion or questions that doesn't represent real issues. T-lang Relevant to the language team T-opsem Relevant to the opsem team

Comments

@kupiakos
Copy link
Contributor

kupiakos commented May 19, 2025

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.

@kupiakos kupiakos added the C-bug Category: This is a bug. label May 19, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label May 19, 2025
@kupiakos
Copy link
Contributor Author

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
Copy link
Member

Veykril commented May 20, 2025

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

@lolbinarycat lolbinarycat added C-discussion Category: Discussion or questions that doesn't represent real issues. T-opsem Relevant to the opsem team and removed C-bug Category: This is a bug. labels May 20, 2025
@Kivooeo Kivooeo linked a pull request May 23, 2025 that will close this issue
3 tasks
@Noratrieb Noratrieb added T-lang Relevant to the language team and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels May 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-discussion Category: Discussion or questions that doesn't represent real issues. T-lang Relevant to the language team T-opsem Relevant to the opsem team
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants