unsafe type casting between wrappers types

44 views Asked by At
struct Wrapper1(u32);

impl Wrapper1 {
    fn inner(&self) -> &u32 {
        &self.0
    }
}

struct Wrapper2(u32);

struct Wrapper3(Wrapper1);

trait GetInner {
 fn inner(&self) -> &Wrapper2;
}

impl GetInner for Wrapper3 {
    fn inner(&self) -> &Wrapper2 {
     let raw_pointer = self.0.inner() as *const u32 as *const Wrapper2;
     unsafe {  &*raw_pointer }
    }
}

I have this snippet of code showcasing a simplification of my problem. I have to rely on unsafe because I cannot just do this:

impl GetInner for Wrapper3 {
    fn inner(&self) -> &Wrapper2   
      &Wrapper2(*self.0.inner())
    }
}

Is it sound? Somebody in my team raised concern about alignment. Somebody else mention we have to use #[repr(transparent)] on the wrappers types in order to make it more safe.

1

There are 1 answers

0
Chayim Friedman On

You need Wrapper2 to be #[repr(transparent)] or #[repr(C)]. Layout of #[repr(Rust) structs is not guaranteed.

However, if you do that, you don't need unsafe anymore - you can use bytemuck:

struct Wrapper1(u32);

impl Wrapper1 {
    fn inner(&self) -> &u32 {
        &self.0
    }
}

#[derive(bytemuck::TransparentWrapper)]
#[repr(transparent)]
struct Wrapper2(u32);

struct Wrapper3(Wrapper1);

trait GetInner {
    fn inner(&self) -> &Wrapper2;
}

impl GetInner for Wrapper3 {
    fn inner(&self) -> &Wrapper2 {
        bytemuck::TransparentWrapper::wrap_ref(self.0.inner())
    }
}