I'm trying to call a C function in Rust, and I met a strange problem. This code reproduces my problem:
C
int t(uint8_t *data){
*data = 1;
*(data+1) = 2;
*(data+2) = 3;
}
// block1
unsafe {
let data = Vec::with_capacity(1024).as_mut_ptr();
t(data);
println!("{:?}", Vec::from_raw_parts(data, 4, 4));
}
// block2
unsafe {
let mut data: Vec<u8> = Vec::with_capacity(1024);
let pdata = data.as_mut_ptr();
t(pdata);
println!("{:?}", Vec::from_raw_parts(pdata, 4, 4));
}
I expect the output to be [1, 2, 3, 0]
.
Only "block2" works, "block1" outputs [91, 57, 49, 44]
. I have no idea where that comes from.
The most confusing thing is that when I put "block1" after "block2" and run them together, they both output [1, 2, 3, 0]
correctly.
What didn't I notice? What's the difference between two blocks?
I believe what is happening here is
let data = Vec::with_capacity(1024).as_mut_ptr();
This is ends up producing undefined behavior. Here, the Vec<T>
is temporary, and so will deallocate its memory after this line runs, so you're passing in a bad pointer to the C.
That you get different results when moving code around also seems to imply there's UB here.