Rust FFI. Casting to void pointer - rust

I've a function which has prototype as below
//opaque struct
struct mosquitto;
struct mosquitto *mosquitto_new(const char *id, bool clean_session, void *obj);
In my c code, I'm calling it as below.
struct mosquitto *m = mosquitto_new(buf, true, NULL);
Now I want to call the above API in my rust code. rust-bindgen generated the following bindings
pub enum Struct_mosquitto { }
pub fn mosquitto_new(id: *const ::libc::c_char, clean_session: u8, obj: *mut ::libc::c_void) -> *mut Struct_mosquitto;
When I'm trying to call the above API, I'm getting a mismatch at 3rd argument.
let s = CString::new("ravi").unwrap();
let mqtt = mosquitto::mosquitto_new(s.as_ptr(), 1, ptr::null());
How do I pass NULL to *mut c_void?
BONUS QUESTION: How to pass a rust struct to *mut c_void ?

The ptr::null() function returns a *const T, what you want is the ptr::null_mut() function, since the argument to your function is of type *mut ::libc::c_void.
For passing an actual value, have a look at the answer to Working with c_void in an FFI

Related

How do I produce an FFI function with a `main`-like interface?

I am trying to use rust to interface with an ancient platform that expects the functions to be declared and externed in a specific C-Style format.
char *func(int argc, char *argv[])
I am trying to reproduce this signature in Rust. I need to be able to properly parse arguments (ideally as Rust Strings) and then return an arbitrary value as a string without disrupting the signature.
So far, I have the following:
#[no_mangle]
pub extern "C" fn my_function(argc: isize, argv: *const c_char) -> (CString) {
let output: CString = CString::new("Test Output").expect("CString::new failed");
return output;
}
Which properly returns my test string through the interface, but I can't figure out how to parse argv into a usable format, or if my implementation of argv is even properly compliant with the specified format. I am not familiar with pointers, and I am not even sure where to start with figuring this out.
With your existing code, you have a few primary issues:
argv: *const c_char is wrong because the original C code is an array of pointers, not a pointer to a char. The correct type is
argv: *const *const c_char
You cannot return CString because that is not a type that C will know what to do with. You need to return *mut c_char just like the C function did. To do this, you use output.into_raw() to unwrap the string and get the underlying *mut c_char pointer. This also means that you are giving this C code a random pointer, and it can read it as a C string, but it can't free that memory, so you're either leaking that memory, or you need a second function to pass the string back to Rust to be freed later using from_raw. In this case I'm using *mut c_char because that's what into_raw returns.
You should consistently use the c_ types for everything in the C interface, including argc, e.g.
my_function(argc: c_int, argv: *const *const c_char) -> *mut c_char
To process the args, you want to loop through the argc values to wrap each pointer into a CStr, which you can then work with without needing to worry about unsafe code.
All taken together:
#[no_mangle]
pub extern "C" fn my_function(argc: c_int, argv: *const *const c_char) -> *mut c_char {
let argv: Vec<_> = (0..argc)
.map(|i| unsafe { CStr::from_ptr(*argv.add(i as usize)) })
.collect();
// Whatever processing you need to do.
let output = CString::new("Test Output").expect("CString::new failed");
return output.into_raw();
}
and potentially
#[no_mangle]
pub extern "C" fn my_function_free(s: *mut c_char) {
unsafe {
CString::from_raw(s);
}
}

Using reference to type parameter in callback function of C library

I am writing a Rust interface to a C library that has a function with the following signature:
typedef int (*callback_t)(const int *a, void *user_data);
void execute(callback_t callback);
What I would like is that the users of the Rust interface can pass any type T for user_data (user_data is not used in the C library). In other words, on the Rust side I would like:
type Callback<T> = fn(a: &mut usize, user_data: &mut T) -> usize;
I tried casting a user-defined Rust function of type Callback<T> to
extern "C" fn callback(a: *mut c_int, user_data: *mut c_void) -> c_int
with as, but that does not work. I also tried to create a wrapping closure. Both attempts did not work.
Can anyone help me out?
You should not be casting function pointers between different signatures. That's catastrophically unsafe and will blow your program up (if you're lucky). Function pointers are not interchangeable, and the compiler cannot magically make them compatible.
What you're effectively doing here is taking an order written in Italian, scratching out "language = Italian", replacing it with "language = Russian", and expecting the Russian chef to understand it because, hey, it says it's in Russian!
First of all, your translation of the raw C type is probably wrong. The first argument is *const c_int, not *mut c_int. C does allow you to cast const away, but it's rarely something the other code will expect.
Secondly, you should not translate raw C pointers as safe Rust references. If the C code calls with a null pointer, your Rust code will have undefined behaviour. Unless the C library guarantees that both pointers are never null with a contract signed in blood and guaranteed with the programmer's first born child, don't trust it: check the pointers first.
Third, c_int and usize are not the same type. Do not conflate them. The correct type to use for the Rust interface is c_int.
So the actual C callback type in Rust is:
type CCallback = Option<extern "C" fn(a: *const c_int, user_data: *mut c_void) -> c_int>;
The Option is there because C function pointers can be null, in Rust they can't.
Finally, Callback<T> isn't marked with extern "C". Getting the calling convention exactly right is of critical importance.
The signature of any function you intend to cast to the C callback type should be exactly the C callback signature. That is:
extern "C" fn a_callback(a: *const c_int, user_data: *mut c_void) -> c_int {
::std::process::abort();
}
Now, you might be able to get away with this:
extern "C" fn a_callback<T>(a: *const c_int, user_data: *mut T) -> c_int {
::std::process::abort();
}
And coerce Some(a_callback) to CCallback. That said, I can't guarantee this is correct for all possible T.
To be safe, you should explicitly wrap all Rust callback functions in a translation function. This is most easily done with a macro that, given the name of the Rust function, generates a C shim.
macro_rules! shim {
($c:ident => $r:ident) => {
extern "C" fn $c(a: *const c_int, user_data: *mut c_void) -> c_int {
if a.is_null() {
::std::process::abort()
}
if user_data.is_null() {
::std::process::abort()
}
// NOTE: You need to make *absolutely certain* that this cast
// of user_data is valid.
let res: i32 = $r(&*a, &mut *(user_data as *mut _));
res as c_int
}
};
}
shim!(another_callback_c => another_callback);
fn another_callback(a: &c_int, user_data: &mut u8) -> i32 {
// Do something...
::std::process::abort()
}

How to get the offset of a struct member in Rust? (offsetof) [duplicate]

I have a type:
struct Foo {
memberA: Bar,
memberB: Baz,
}
and a pointer which I know is a pointer to memberB in Foo:
p: *const Baz
What is the correct way to get a new pointer p: *const Foo which points to the original struct Foo?
My current implementation is the following, which I'm pretty sure invokes undefined behavior due to the dereference of (p as *const Foo) where p is not a pointer to a Foo:
let p2 = p as usize -
((&(*(p as *const Foo)).memberB as *const _ as usize) - (p as usize));
This is part of FFI - I can't easily restructure the code to avoid needing to perform this operation.
This is very similar to Get pointer to object from pointer to some member but for Rust, which as far as I know has no offsetof macro.
The dereference expression produces an lvalue, but that lvalue is not actually read from, we're just doing pointer math on it, so in theory, it should be well defined. That's just my interpretation though.
My solution involves using a null pointer to retrieve the offset to the field, so it's a bit simpler than yours as it avoids one subtraction (we'd be subtracting 0). I believe I saw some C compilers/standard libraries implementing offsetof by essentially returning the address of a field from a null pointer, which is what inspired the following solution.
fn main() {
let p: *const Baz = 0x1248 as *const _;
let p2: *const Foo = unsafe { ((p as usize) - (&(*(0 as *const Foo)).memberB as *const _ as usize)) as *const _ };
println!("{:p}", p2);
}
We can also define our own offset_of! macro:
macro_rules! offset_of {
($ty:ty, $field:ident) => {
unsafe { &(*(0 as *const $ty)).$field as *const _ as usize }
}
}
fn main() {
let p: *const Baz = 0x1248 as *const _;
let p2: *const Foo = ((p as usize) - offset_of!(Foo, memberB)) as *const _;
println!("{:p}", p2);
}
With the implementation of RFC 2582, raw reference MIR operator, it is now possible to get the address of a field in a struct without an instance of the struct and without invoking undefined behavior.
use std::{mem::MaybeUninit, ptr};
struct Example {
a: i32,
b: u8,
c: bool,
}
fn main() {
let offset = unsafe {
let base = MaybeUninit::<Example>::uninit();
let base_ptr = base.as_ptr();
let c = ptr::addr_of!((*base_ptr).c);
(c as usize) - (base_ptr as usize)
};
println!("{}", offset);
}
The implementation of this is tricky and nuanced. It is best to use a crate that is well-maintained, such as memoffset.
Before this functionality was stabilized, you must have a valid instance of the struct. You can use tools like once_cell to minimize the overhead of the dummy value that you need to create:
use once_cell::sync::Lazy; // 1.4.1
struct Example {
a: i32,
b: u8,
c: bool,
}
static DUMMY: Lazy<Example> = Lazy::new(|| Example {
a: 0,
b: 0,
c: false,
});
static OFFSET_C: Lazy<usize> = Lazy::new(|| {
let base: *const Example = &*DUMMY;
let c: *const bool = &DUMMY.c;
(c as usize) - (base as usize)
});
fn main() {
println!("{}", *OFFSET_C);
}
If you must have this at compile time, you can place similar code into a build script and write out a Rust source file with the offsets. However, that will span multiple compiler invocations, so you are relying on the struct layout not changing between those invocations. Using something with a known representation would reduce that risk.
See also:
How do I create a global, mutable singleton?
How to create a static string at compile time

What's the Rust idiom to define a field pointing to a C opaque pointer?

Given a struct:
#[repr(C)]
pub struct User {
pub name: *const c_char,
pub age: u8,
pub ctx: ??,
}
the field ctx would only be manipulated by C code; it's a pointer to a C struct UserAttr.
According to the Rust FFI documentation, the choice would be defined as an opaque type pub enum UserAttr {}. However, I found that Rust is unable to copy its value, e.g. why does the address of an object change across methods.
What's the right way in Rust to define such an opaque pointer, so that its value (as a pointer) gets copied across methods?
The future
RFC 1861 introduced the concept of an extern type. While implemented, it is not yet stabilized. Once it is, it will become the preferred implementation:
#![feature(extern_types)]
extern "C" {
type Foo;
}
type FooPtr = *mut Foo;
Today
The documentation states:
To do this in Rust, let’s create our own opaque types:
#[repr(C)] pub struct Foo { private: [u8; 0] }
#[repr(C)] pub struct Bar { private: [u8; 0] }
extern "C" {
pub fn foo(arg: *mut Foo);
pub fn bar(arg: *mut Bar);
}
By including a private field and no constructor, we create an opaque
type that we can’t instantiate outside of this module. An empty array
is both zero-size and compatible with #[repr(C)]. But because our
Foo and Bar types are different, we’ll get type safety between the
two of them, so we cannot accidentally pass a pointer to Foo to
bar().
An opaque pointer is created such that there's no normal way of creating such a type; you can only create pointers to it.
mod ffi {
use std::ptr;
pub struct MyTypeFromC { _private: [u8; 0] }
pub fn constructor() -> *mut MyTypeFromC {
ptr::null_mut()
}
pub fn something(_thing: *mut MyTypeFromC) {
println!("Doing a thing");
}
}
use ffi::*;
struct MyRustType {
score: u8,
the_c_thing: *mut MyTypeFromC,
}
impl MyRustType {
fn new() -> MyRustType {
MyRustType {
score: 42,
the_c_thing: constructor(),
}
}
fn something(&mut self) {
println!("My score is {}", self.score);
ffi::something(self.the_c_thing);
self.score += 1;
}
}
fn main() {
let mut my_thing = MyRustType::new();
my_thing.something();
}
Breaking it down a bit:
// opaque -----V~~~~~~~~~V
*mut MyTypeFromC
// ^~~^ ------------ pointer
Thus it's an opaque pointer. Moving the struct MyRustType will not change the value of the pointer.
The past
Previous iterations of this answer and the documentation suggested using an empty enum (enum MyTypeFromC {}). An enum with no variants is semantically equivalent to the never type (!), which is a type that cannot exist. There were concerns that using such a construct could lead to undefined behavior, so moving to an empty array was deemed safer.

Is it possible to call a Rust function taking a Vec from C?

Suppose I have the following Rust library:
// lib.rs
#![crate_type = staticlib]
#[no_mangle]
pub extern fn do_something(number: i32) {
// something
}
#[no_mangle]
pub extern fn do_something_else(collection: &Vec<i32>) {
// something
}
I know that, to call do_something from C, I'd just need to declare an extern function taking an int32_t, but is it possible to call do_something_else? If so, how?
You can, but the better question is should you?
Since you cannot construct a Vec from C, you'd have to construct it in Rust and then return a pointer to C. C code would own the pointer to the Vec and would then pass it back when calling do_something_else.
Then there's the problem that you can't really modify the Vec in C either, other than by creating new FFI methods that mirror all of the Rust methods.
You also probably shouldn't take a &Vec<i32> because Rust references are guaranteed to not be NULL, and there's nothing that enforces that when called from C. It's better to take a *const Vec<i32>, assert that it's non-NULL and convert it to a reference.
Chances are that you want to accept a C array through the FFI boundary. C arrays are a pointer and a length, so you'd accept both and reconstitute a Rust slice (since you wouldn't own the array):
use std::slice;
pub extern fn do_something_else(p: *const i32, len: libc::size_t) {
let slice = unsafe {
assert!(!p.is_null());
slice::from_raw_parts(p, len)
};
}
Obligatory link to The Rust FFI Omnibus.
If you really needed to do what you asked, it would probably look something like this:
extern crate libc;
#[no_mangle]
pub extern fn make_vec() -> *mut Vec<i32> {
Box::into_raw(Box::new(Vec::new()))
}
#[no_mangle]
pub extern fn add_number(vec: *mut Vec<i32>, val: libc::int32_t) {
let vec = unsafe {
assert!(!vec.is_null());
&mut *vec
};
vec.push(val);
}
#[no_mangle]
pub extern fn print_vec(vec: *const Vec<i32>) {
let vec = unsafe {
assert!(!vec.is_null());
&*vec
};
println!("{:?}", vec);
}
#[no_mangle]
pub extern fn drop_vec(vec: *mut Vec<i32>) {
unsafe {
assert!(!vec.is_null());
Box::from_raw(vec);
}
}
And would be used like (untested):
// Add extern declarations
int main(int argc, char *argv[]) {
void *v = make_vec(); // Use a real typedef here
add_number(v, 42);
print_vec(v);
drop_vec(v);
}
You'd want to run this under valgrind to make sure I didn't do anything stupid memory-wise.

Resources