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'

      

+9


source to share


2 answers


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:

+8


source


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

.

0


source







All Articles