Hello all. Recently I decided to try out rust to complete the other half of a simple portable executable loader I was working because Rust sounds appealing.
In C, I would cast the required structs from a pointer to parse the exe, as so:
I was looking for the proper way to do such things in rust, and found some code online that I tried to implement quickly to check for functionality. It worked, and the struct was filled with the required data, but I really am not sure why a certain line functions.
unsafe {
let struct_slice = std::slice::from_raw_parts_mut(&mut dos as *mut _ as *mut u8, 512);
stubsl.read_exact(struct_slice).unwrap();
}
The "&mut dos as *mut _ as *mut" is pretty confusing. I am unsure why it enables the arbitrary pointer type cast. Can anyone explain why the underscore cast lets the cast happen?
Also, if anyone has any pointers on the proper/safe way to parse binary formats in Rust then I would be very appreciative of any advice.
You coerce your mutable reference to dos to a raw pointer to the type of dos and then coerce this raw pointer to a raw pointer pointing to a byte. The _ is just a placeholder for the compiler to infer the type of the first raw pointer in your coercion chain points to from &mut dos. Direct coercion from &mut T to *mut u8 is not supported by the compiler (read more about supported coercions here), so you got the coercion chain of &mut T -> *mut T -> *mut u8.
You can replace the _ placeholder with the type of dos to make the coercion more readable, i.e.:
struct T;
fn main() {
let mut dos: T = T;
unsafe {
let struct_slice = std::slice::from_raw_parts_mut(&mut dos as *mut T as *mut u8, 512);
}
}
_ in type position means "infer". While a regular reference can't be directly cast to a raw pointer of mismatching type, raw pointers can. So &mut dos as *mut _ converts from a reference to a raw pointer of the matching referent type, and then as *mut u8 performs the actual type conversion (from whatever the original pointee type was to u8).