Defining a "custom" UB for object-to-primitive transmutation
⚓ Rust 📅 2025-05-26 👤 surdeus 👁️ 11A bit of context
Reading through the docs, I noticed an extremely interesting claim:
Note that it is undefined behavior to
transmutefromDiscriminantto a primitive!
<...>// ⚠️ This is undefined behavior. Don't do this. ⚠️ // assert_eq!(0, unsafe { std::mem::transmute::<_, u8>(std::mem::discriminant(&unit_like)) });
There is an unsafe block so std is totally free to define this as UB as if std::hint::unreachable_unchecked() was called... though... how is it done, exactly?
Discriminant reading can be moved out of the block, the only unsafe operation is std::mem::transmute call so it must be the one invoking UB. There seem to be two possible options which it is:
-
[undefined.intrinsic] Invoking undefined behavior via compiler intrinsics.
I would imagine this like "transmute may check whether the source type isDiscriminant<T>, and if it is, insert a spuriousunreachable_unchecked()call". Doesn't seem applicable to other ways of reinterpreting a value (likeptr::read_unaligned) though. -
[undefined.invalid] Producing an invalid value.
However, the only invalid value I know for the primitive number types is uninitialized memory.
It is certainly possible, and no trait onDiscriminant<T>rules that out.
Question
Now, my question is: if one day I decided to make a structure S which would invoke immediate UB upon attempt to transmute it to primitive, what could I do? One option I see is carrying around a MaybeUninit<...> to have some uninit bytes in the struct.
2 posts - 2 participants
🏷️ rust_feed