Is the layout of a wide pointer stable?

Is the layout of a wide pointer, i.e. to a slice, stable? For example, would

let slice: *const [u8] = 
    unsafe { std::mem::transmute([0u8; std::mem::size_of::<usize>() * 2]) };

be sound, and create a valid (albeit null) slice pointer?

No. Use std::slice::from_raw_parts. See also the safety notes on that page, including the one about NonNull::dangling().

You can get the thin pointer from slice as *const [T] as *const T, for an existing slice.

1 Like

I'm aware of that, I was just wondering if this was technically allowed, even if there was a better way to do it.

I think my example is more like std::ptr::slice_from_raw_parts, which doesn't require it be non-null

It's not "allowed" (guaranteed to work). Personally I consider the layout unlikely to change, but officially the layout is not guaranteed and rustc (or any other compiler) can change the layout (or choose a different layout from the start), and any fallout would not be considered a breaking change.

(Even if it never changes, it's generally considered better to use a type-specific transformation than transmute when possible, e.g. std::str::from_utf8_unchecked.)

And you're right, I should have suggested that one given your example, and you can make a *const [T] out of a null pointer (so long as you don't do much with it).

2 Likes

Do not use transmute for converting between pointers! Transmuting isn't transitive – if you have two value types T and U that can be safely transmuted into each other, it is not in general true that you can also transmute &T to &U. If you are trying to perform a pointer conversion, use as casts or the aforementioned unsafe functions.

3 Likes

The layout of a wide pointer is completely unspecified. Don't use transmutes for this.

5 Likes

Huh, I had no idea about this

Thanks. I was hoping to be able to make wide pointers by hand, but I guess I'll just wait for ptr_metadata to be stabilized

Simple example: you can transmute [u8; 4] to u32 soundly (though you should of course use from_ne_bytes instead for that) but &[u8; 4] to &u32 could be underaligned, and thus might be UB.

1 Like

Ah, makes perfect sense. Thanks!

If like me this come as a bit surprising to you, here is what the doc says:

transmute is semantically equivalent to a bitwise move of one type into another. It copies the bits from the source value into the destination value, then forgets the original. It’s equivalent to C’s memcpy under the hood, just like transmute_copy .

Because transmute is a by-value operation, alignment of the transmuted values themselves is not a concern. As with any other function, the compiler already ensures both T and U are properly aligned. However, when transmuting values that point elsewhere (such as pointers, references, boxes…), the caller has to ensure proper alignment of the pointed-to values.

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.