I started experimenting a bit with FFI and bindings for some C libraries, and have some questions regarding the scope of structs along with raw pointers.
I used bindgen
to create bindings for a C library. The generated bindings use c_void
in arguments quite heavily for callbacks to first initialize a context:
fn some_init_func(context: *mut *mut c_void, ...)
updating it:
fn some_update_func(context: *mut c_void, ...)
and eventually some action/finalizing:
fn some_action_func(context: *mut c_void, ...)
So I type cast the raw c_void
pointer to a Rust struct
I'd like to work with and then modify it as required. For example, simplifying the some_init_func
above:
fn some_init_func(context: *mut *mut c_void, ...) {
let mut rust_context = MyContext::new();
...
let raw_rust_context = &mut rust_context as *mut _ as *mut c_void;
*context = raw_rust_context;
}
Question 1
In this case, will the raw pointer argument context
still be valid after some_init_func
has run? To me it feels like Rust would drop the struct rust_context
(since it's only scoped to this function), does it also clean up the memory so the raw context pointer would not be correctly initialized any more? The rust book, in the chapter on unsafe, says:
Raw pointers don't have any automatic clean up
I'm not sure I understand it in the example above.
Question 2
Later on, when a callback occurs to the function that prepares and updates some field in this context struct, I type cast the argument to a struct again but do I also need to cast it back to a raw pointer after mutating it?
fn some_update_func(context: *mut c_void, ...) {
let mut rust_context = &mut *(context as *mut MyContext);
rust_context.index = 42;
// Is the above enough to update the raw pointer context? Or do I need to also
// cast the rust Struct back to a raw pointer and reassign to context?
// e.g.
// let raw_rust_context = &mut rust_context as *mut _ as *mut c_void;
// *context = raw_rust_context;
}