How do I initialize an opaque C struct when using Rust FFI?
This is what I would like to do in C code:
#include <some_lib.h>
int main() {
some_lib_struct_t x;
some_lib_func(&x);
}
How do I use a library in Rust? Here's what I've got so far:
extern crate libc; // 0.2.51
struct some_lib_struct_t;
#[link(name = "some_lib")]
extern "C" {
fn some_lib_func(x: *mut some_lib_struct_t);
}
fn main() {
let mut x: some_lib_struct_t;
unsafe {
some_lib_func(&mut x);
}
}
When compiling, I get the error:
error[E0381]: borrow of possibly uninitialized variable: 'x' --> src/main.rs:13:23 | 13 | some_lib_func(&mut x); | ^^^^^^ use of possibly uninitialized 'x'
source to share
The safest answer is to initialize the structure yourself:
let mut x: some_lib_struct_t = some_lib_struct_t;
unsafe {
some_lib_func(&mut x);
}
The closest analogue to C code is to use mem::uninitialized
:
unsafe {
let mut x: some_lib_struct_t = std::mem::uninitialized();
some_lib_func(&mut x);
}
You must be sure to some_lib_func
fully initialize all members of the structure, otherwise insecurity will leak outside the block unsafe
.
In terms of "members", I almost guarantee that your code won't do what you want. You have defined some_lib_struct_t
as having a size of zero. This means that no stack space will be allocated for it, and the reference to it will not be what your C code expects.
You need to mirror the definition of the C structure in Rust so that you can assign the appropriate size, padding, and alignment. This usually means using repr(C)
.
Many times the C libraries avoid exposing them to their internal structural representation by always returning a pointer to an opaque type:
source to share
After reading Shepmaster's answer , I looked closely at the header of the library. As they said, there some_lib_struct_t
was just a typedef for a pointer to actual_lib_struct_t
. I made the following changes:
extern crate libc;
struct actual_lib_struct_t;
type some_lib_type_t = *mut actual_lib_struct_t;
#[link(name="some_lib")]
extern {
fn some_lib_func(x: *mut some_lib_type_t);
}
fn main() {
let mut x: some_lib_type_t;
unsafe {
x = std::mem::uninitialized();
some_lib_func(&mut x);
}
}
And it works! However, I am getting a warning about found zero-size struct in foreign module, consider adding a member to this struct, #[warn(improper_ctypes)] on by default
.
source to share