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?
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.
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).
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.
The layout of a wide pointer is completely unspecified. Don't use transmutes for this.
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.
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’smemcpy
under the hood, just liketransmute_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 bothT
andU
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.