How to truncate a reference to a dynamic sized struct?

How can I truncate the length of a reference to a dynamic sized struct? E.g.:

struct DynamicLength {
    meta: u32,
    data: [u8]
}
impl DynamicLength {
    fn truncated(&self, length: usize) -> &Self {
        // what goes here?
    }
}

That kind of struct works very poorly. I don't think it is possible currently.

1 Like

Oh. That's a shame. I'll have to find another way to do what I need.

Maybe something like the following will work?

unsafe {
    let self_ptr = self as *const DynamicLength as *const [u8];
    // Cast to `MaybeUninit<u8>` technically only necessary when `meta` can have padding.
    let self_slice_ref = &*(self_ptr as *const [MaybeUninit<u8>]);
    assert!(self_slice_ref.len() <= length);
    let truncated_self_ptr = std::ptr::slice_from_raw_parts(self_ptr as *const u8, length) as *const DynamicLength;
    &*truncated_self_ptr
}

Basically first cast self to *const [u8] then truncate the length and turn it back into an &DynamicLength.

1 Like

I don't want to question the unsafe part, just this:

Shouldn't this be reversed? For now, it seems you're not truncating, but expanding - and that's, well, obviously not good.

1 Like

Oops, it indeed needs to be reversed.

This worked! And miri seems happy enough, which is something.

When the UB is relying on an implementation detail of how something is represented, miri is not able to catch it.