I'm trying to understand some of the rules around transmute
but I'm seeing stuff that seems contradictory. Here's an example program that I'd like to be able to write soundly, but currently fails Miri:
fn main() {
let pointer: Box<i32> = Box::new(123);
let p_bytes: [u8; size_of::<Box<i32>>()] = unsafe { transmute(pointer) };
let pointer_again: Box<i32> = unsafe { transmute(p_bytes) };
assert_eq!(*pointer_again, 123);
}
Running this with miri gives the following:
error: Undefined Behavior: type validation failed: encountered a dangling box (address 0x28ca8 is unallocated)
--> src/main.rs:7:44
|
7 | let pointer_again: Box<i32> = unsafe { transmute(p_bytes) };
| ^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling box (address 0x28ca8 is unallocated)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
Unfortunately the link doesn't help much with this question.
The general question I have is: "why is this UB". Googling this error message hasn't been particularly successful, but it generally indicates that this might be an issue with pointer provenance, but I was under the impression that pointer provenance rules currently aren't enforced by Rust. Is that correct? Or is miri being overly cautious here? Is there actual risk of something going wrong?
This is confusing me because the docs of transmute
seem to have a few places where pointer-like types are transmuted (e.g. Vec
, &str
, &[u8]
).
Moreover, if I make p_bytes
have type usize
, I get a different error (for a dangling box when doing the second transmute), which to me implies that the first error was fixed. But this is also confusing. Does passing pointer
into transmute
run its Drop
implementation when transmute
ends (since it passes ownership)?
Thanks in advance