I was trying to fill a slightly awkward FFI structure using ptr::copy and my app crashed. When debugging, I realized that copy(slice, ...) behaves differently than copy(slice.as_ptr(), ...), which I found surprising.
Here is the code in question:
#[derive(Debug)]
struct S {
array: [u8; 256],
}
fn main() {
let mut s = S { array: [0; 256] };
let hello = b"hello world\0";
unsafe {
std::ptr::copy(hello , s.array.as_mut_ptr() as *mut _, hello.len()); // causes UB
//std::ptr::copy(hello.as_ptr(), s.array.as_mut_ptr() as *mut _, hello.len()); // OK
dbg!(hello as *const _); // [src\main.rs:15] hello as *const _ = 0x00007ff7f2a9e3d8
dbg!(hello.as_ptr() as *const _); // [src\main.rs:16] hello.as_ptr() as *const _ = 0x00007ff7f2a9e3d8
}
dbg!(s);
}
The first copy causes UB, which is confirmed by Miri, and the output if dbg!(s) is garbled.
The second copy works as expected.
Why is that? Both debug lines below print the same address (e.g., 0x00007ff7f2a9e3d8), and I thought that a slice pointer can be automatically coerced to a pointer to the first element?
Type inference tripped you up. A pointer-to-array doesn't automatically become a pointer-to-element, so your types got inferred to be *const [u8; 12], which is too big. Being more explicit works under MIRI too:
std::ptr::copy(hello as *const _ as *const u8, s.array.as_mut_ptr() as *mut u8, hello.len());
In general, you should always be explicit with your types in unsafe.
The variable hello's type is &'static [u8; 12], so std::ptr::copy(hello, some_ptr, hello.len()) will copy 12 * 12 = 144 bytes. Copying 144 bytes from it indeed is UB.
In situations like this, it might be useful to be explicit in the type of the copy:
std::ptr::copy::<u8>(...);
This way, you're not relying on anything about the arguments to ensure that the operation is doing what you expect, and a reader can instantly see "this is copying a certain count of u8s". (I've found this approach useful in non-unsafe code using bytemuck, where even if there's no UB, converting the wrong type will result in the wrong result.)