Description
If you have a C API taking a pointer-to-a-pointer, like void**
, where the function fills in a pointer value, it's very easy to screw up if there is any pointer casting involved:
extern crate libc;
extern {
fn c_func(x: *mut *mut libc::c_void);
}
fn main() {
let x = 0 as *mut u8;
c_func(&mut (x as *mut libc::c_void));
println!("new pointer is {}", x);
}
This will always print new pointer is 0x0
, no matter what c_func
does.
Reason: the x as *mut ...
cast is creating a temporary, that's disconnected from the original x
and thus the modification happens to the anonymous stack slot that stores the result of the cast. The code should be written something like (&mut x) as *mut _ as *mut *mut libc::c_void
.
This is really subtle to debug, so we could have a lint that assists in this case: "did you mean to take a reference to the result of a cast in this FFI call" (could have it apply to non-FFI things too, and presumably it should only apply when there are &mut
pointers involved).