The following program fails to run in Miri with an unaligned memory access:
use rand::Rng;
fn main()
{
let mut rng = rand::thread_rng();
let _val = rng.gen::<i32>();
let _val = rng.gen::<usize>(); // causes unaligned memory access
}
This is caused by this line of code:
|
unsafe { *(&results[index] as *const u32 as *const u64) } |
That casts a 4-aligned pointer to a *const i64 and then uses that for a read. i64 reads must be 8-aligned. There is a comment in the souce indicating that this "requires little-endian CPU supporting unaligned reads", but that is not sufficient: the alignment requirement is made by LLVM, not by the CPU. In Rust, all accesses must be aligned on all platforms, no matter what the CPU says; any unaligned access causes UB (on all platforms). Unaligned accesses are only allowed with read_unaligned and write_unaligned.
There is another problem with this code as well: It violates pointer provenance rules. &results[index] as *const u32 creates a raw pointer that may be used to access this particular element, but it is not legal to use this pointer to access neighboring elements that were never cast to a raw pointer. You could try to fix this with something like &results[index..index+1] as *const [u32] as *const u32 as *const u64.
Is the performance of the "fallback code path" really so much worse that all these hacks are worth it?
The following program fails to run in Miri with an unaligned memory access:
This is caused by this line of code:
rand/rand_core/src/block.rs
Line 186 in 852988b
That casts a 4-aligned pointer to a
*const i64and then uses that for a read.i64reads must be 8-aligned. There is a comment in the souce indicating that this "requires little-endian CPU supporting unaligned reads", but that is not sufficient: the alignment requirement is made by LLVM, not by the CPU. In Rust, all accesses must be aligned on all platforms, no matter what the CPU says; any unaligned access causes UB (on all platforms). Unaligned accesses are only allowed withread_unalignedandwrite_unaligned.There is another problem with this code as well: It violates pointer provenance rules.
&results[index] as *const u32creates a raw pointer that may be used to access this particular element, but it is not legal to use this pointer to access neighboring elements that were never cast to a raw pointer. You could try to fix this with something like&results[index..index+1] as *const [u32] as *const u32 as *const u64.Is the performance of the "fallback code path" really so much worse that all these hacks are worth it?