Is it safe to transmute slices of transparent structs of byte arrays from byte slices?

I have a use-case for which I want to interpret a slice of bytes as a slice of structs.

For that I was thinking to use a chain of transformations:

  1. [u8] -> [[u8; SIZE]]
  2. [[u8; SIZE]] to [A] (transparent struct with [u8; SIZE] member)

Is this overall transformation safe to do? I know that individual transparent structs are safe to transmute (thanks to transparent), but I could not find anything documented about slices of transparent structs, nor about the safety of converting a slice into a nested slice of arrays.

Example (Playground)

#[repr(transparent)]
struct A {
    data: [u8; 16],
}

impl A {
    fn set_x(&mut self, value: u8) {
        self.data[3] = value;
    }

    fn x(&self) -> u8 {
        self.data[3]
    }
}

fn reinterpret(data: &mut [u8]) -> &mut [A] {
    assert!(data.len() % 16 == 0);
    let ptr : *mut u8 = data.as_mut_ptr();
    let a_ptr = ptr as *mut A;
    unsafe { std::slice::from_raw_parts_mut(a_ptr, data.len() / 16) }
}

fn main() {
    let mut data_bytes = vec![0; 10 * 16];
    let data = reinterpret(&mut data_bytes);
    for (i, a) in data.iter_mut().enumerate() { a.set_x(i as u8); }
    for a in data { println!("{}", a.x( )); }
}

Yes, this appears safe to me.

  • The signature of reintepret ensures that the underlying byte slice is borrowed as long as the returned [A] slice is alive, so there are no aliasing or use-after-free issues possible in safe code.
  • You ensure that the lengths of the slices match.
  • There are no alignment issues because all of the types involved have 1 byte alignment.
  • A has no padding or invalid values.
2 Likes

This is a situation where the ::bytemuck crate shines: https://docs.rs/bytemuck/1.2.0/bytemuck/fn.try_cast_slice.html

You'll just need to unsafe impl Zeroable for A {} unsafe impl Pod for A {}

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.