Soundness about `transmute` `Vec<Vec<u8>>` to `Vec<String>>`?

I have some Vec<u8> with every u8 a surely ascii, but I get scared to transmute Vec<Vec<u8>> to Vec<String>, because I know #[repr(Rust)] may mess up the original order of Vec<T>(really?), or if there are any other constraints in transmute that I could have violated?
More specifically, is there a formal documentation showing when will #[repr(rust)] reorder the data field? I know Vec<T> occupies exactly 3 * usize bytes without any hole, but still not sure about it.

If you just do my_vec_of_vecs.into_iter().map(|v| unsafe { String::from_utf8_unchecked(v) }).collect::<Vec<_>>() the compiler will hopefully optimize it down to nothing, and you don't have to worry about transmute.


Since there are no guarantees about the order of fields in #[repr(rust)] structs, there's nothing guaranteeing that Vec<T> and Vec<U> have the same field order even if T and U have the same layout. However, you could get around this by using Vec::from_raw_parts instead of transmute to convert between them:

pub unsafe fn convert(mut v: Vec<Vec<u8>>) -> Vec<String> {

(Strictly speaking, I don't think there's any documented guarantee that String has the same layout as Vec<u8>. However, there are guarantees about String representation and Vec representation. Combined with the existence of String::as_mut_vec, these guarantees imply that String must have the same layout as Vec<u8>.)

Thanks! But I find that your convert makes a dangling pointer.
I think it should be like the following?

pub unsafe fn convert(v: Vec<Vec<u8>>) -> Vec<String> {
        let mut wrapper = ManuallyDrop::new(v);

Yes, good catch.

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.