Any safety/provenance difference between ways of casting byteslice to integer?

#![allow(dead_code)]

unsafe fn v1(x: &[u8]) -> &u32 {
    &*(x.as_ptr() as *const u32)
}

unsafe fn v2(x: &[u8]) -> &u32 {
    &*(&x[0] as *const u8 as *const u32)
}

unsafe fn v3(x: &[u8]) -> &u32 {
    &*(x as *const [u8] as *const u32)
}

Are these all equally valid? unsafe due to assumption slice is memory sufficiently aligned for u32. I know this is ignoring endianness, just trying to understand if the provenance of these differ, e.g. does &x[0] narrow us down to only looking at the first element, so using it to produce a u32 pointer that touches the rest of the slice may be UB?

AFAIK, it does, so this does make a difference. Have you checked what miri has to say when testing these code examples?

Edit: As expected, miri does report the difference. Run it under "Tools" in this playground: Rust Playground

4 Likes

That's an interesting way to align a repr(C) struct:

#[repr(C)]
struct Align([u32; 0], [u8; 4]);

I haven't seen it anywhere before, probably because C itself disallows length-0 array members. I guess it uses the requirement that &align.0 as &[u32] must be properly aligned?

The two other methods are fine, for the record.

Yep miri agrees the other two work. Thanks all.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.