Yes, it is, or more precisely, it ought to be valid. (Except that you have a type error down in the call, because if the function is declared to take
Box<T>, then you should pass the box directly instead of calling
Box<T> does NOT change the FFI-safety of its contained value type. It neither removes nor adds FFI-safety.
Link to the relevant URLO thread, and to the docs that explicitly state:
So long as
T: Sized , a
Box<T> is guaranteed to be represented as a single pointer and is also ABI-compatible with C pointers (i.e. the C type
And to the announcement of Rust 1.41 which also explicitly says:
Starting with Rust 1.41.0, we have declared that a
Box<T> , where
T: Sized is now ABI compatible with the C language's pointer (
T* ) types. So if you have an
extern "C" Rust function, called from C, your Rust function can now use
Box<T> , for some specific
T , while using
T* in C for the corresponding function.
Except that the other direction (Rust calling into C) comes with a warning, whereby a bug in LLVM may still cause UB in valid code, so they do indeed advise programmers to mirror the C types as precisely as possible (using raw pointers in this case) as a best practice. But unless you hit this LLVM bug, passing a
Box<T> should work in theory, it should be equivalent with transferring ownership and passing a raw pointer, and once the LLVM bug is fixed, it will also be reliable in practice.
As to why you are getting the warning: it's an unavoidable false positive, no matter which approach you choose, the
Box or the raw pointer. The compiler can't possibly know whether you will actually dereference the pointer on the C side, since it doesn't, it can't, analyze your C code (and for all intents and purposes, you might as well be linking to an opaque library without source).
So it's merely being conservative, emitting the warning anyway, because it's better to get a false positive warning (that you can suppress explicitly if you promise you won't dereference the pointer from C) than it is to get a false negative and silently cause UB if you simply forgot to add the
#[repr(C)] on your
struct that you do however intend to dereference from C.
The safest way to solve this issue is, however, to use an opaque pointer instead. Take
void * on the C side, cast to
*mut c_void on the Rust side, and this guarantees (quasi, modulo arcane C hacks) that you won't be able to dereference the pointer on the C side, and this makes the warning go away without needing to slap an
#[allow(improper_ctypes)] on your
(Note that this still doesn't allow you to violate the "single ownership" and "no mutable aliasing" rules, so you will have to enforce those on your own, paying special attention to the C code and the interaction between the C and the Rust parts of the code.)