Is it safe to cast `&[u8]` to `&AlignedBuf([u8])`?

In my code I want to work with buffers which have a guaranteed alignment, so I created the following helper type:

#[repr(align(8))]
pub struct AlignedBuf(pub [u8]);

impl AlignedBuf {
    /// # Safety
    /// `p` MUST have alignment equal to 8.
    pub unsafe fn from_raw_parts<'a>(p: *const u8, len: usize) -> &'a Self {
        debug_assert_eq!(p as usize % 8, 0);
        debug_assert_eq!(len % 8, 0);
        unsafe {
            let s: &[u8] = core::slice::from_raw_parts(p, len);
            &*(s as *const [u8] as *const Self)
        }
    }
}

I think this code should be sound (assuming the methods are used with correct p and len) and it passes Miri without issues. But on the other hand the Nomicon states:

Currently the only properly supported way to create a custom DST is by making your type generic and performing an unsizing coercion

Should I read it as that the casts are not currently allowed?

This needs to be #[repr(C, align(8))]

Should I read it as that the casts are not currently allowed?

The Nomicon is not very up-to-date about what is allowed. But, it doesn't seem like the Reference actually says anything about the characteristics of pointers to custom DSTs, either — no, actually, by starting from unsafe-code-guidelines#288 I found Pointer-to-pointer cast which specifies your case:

  • If T and U are both unsized, the pointer is also returned unchanged. In particular, the metadata is preserved exactly. … The same holds for str and any compound type whose unsized tail is a slice type, such as struct Foo(i32, [u8]) or (u64, Foo).

Also, the unstable std::ptr::from_raw_parts and its trait offer the same guarantee in a more explicit form without pointer casts.

1 Like