Description
During safety-dance audit I've encountered the following unsafe code pattern that can be converted to safe code:
fn read_u32(bytes: &[u8]) -> u32 {
assert!(bytes.len() >= 4); // bounds check
unsafe { ptr::read_unaligned(*bytes as *const u32)}
}
This is common in binary format decoders that need to take a chunk of byte stream and interpret it as a value. The exact target value may vary - it can be any primitive numerical type.
Ever since TryInto got stabilized this can be rewritten in safe code with identical performance, although the safe solution is not really obvious:
fn read_u32(bytes: &[u8]) -> u32 {
// try_into() cannot fail because slice len is always 4
let bytes_to_convert: [u8; 4] = bytes[..4].try_into().unwrap();
u32::from_ne_bytes(bytes_to_convert)
}
This may look like it does a lot of more and would be slower, but rustc produces identical code for both versions.
If converting to f32 or f64, the last line would instead be the following: f32::from_bits(u32::from_ne_bytes(bytes_to_convert))
See from_bits()
documentation for more info on converting bytes to floats.