Returning array from Rust to FFI - rust

I need to write a function that returns array of u16 integers in Rust. This function then should be used by FFI.
extern crate libc;
use libc::{uint16_t};
#[no_mangle]
pub extern fn ffi_test() -> *const uint16_t {
let test: [u16;4] = [1,2,3,4];
test.as_ptr()
}
Rust code compiles without errors. I used Ruby to test the ffi call:
# coding: utf-8
require 'ffi'
module MyMod
extend FFI::Library
ffi_lib 'my_ffi_test_lib'
attach_function :ffi_test, [], :pointer
end
a_ptr = MyMod.ffi_test
size = 4
result_array = a_ptr.read_array_of_uint16(size)
p result_array
But the results are totally wrong (expected: [1, 2, 3, 4]):
$ ruby ffi_test.rb
[57871, 25191, 32767, 0]
As if I am reading totally diffirent memory addr. I assume maybe that I should not use #as_ptr() on Rust array?
EDIT
As per recommendation of #FrenchBoiethios I tried to box the array:
extern crate libc;
use libc::{uint16_t};
#[no_mangle]
pub extern fn ffi_test() -> *mut uint16_t {
let test: [u16;4] = [1,2,3,4];
let b = Box::new(test);
Box::into_raw(b)
}
This gives compile error:
note: expected type `std::boxed::Box<u16>`
found type `std::boxed::Box<[u16; 4]>`

Your array is on the stack, so there is a lifetime issue when you returns it as a pointer (returned pointer to a local variable). You must allocate it in the heap:
#[no_mangle]
pub extern "C" fn ffi_test() -> *mut u16 {
let mut test = vec![1, 2, 3, 4];
let ptr = test.as_mut_ptr();
std::mem::forget(test); // so that it is not destructed at the end of the scope
ptr
}
or
#[no_mangle]
pub extern "C" fn ffi_test() -> *mut u16 {
let test = Box::new([1u16, 2, 3, 4]); // type must be explicit here...
Box::into_raw(test) as *mut _ // ... because this cast can convert
// *mut [i32; 4] to *mut u16
}

I am trying to learn Rust ffi, those implementations are a frankenstein creation from different sources in internet. So take it with a grain of salt.
Currently I am with two approaches:
a) Remove the array from rust GC and return the point. User need to promise to call free later.
#[repr(C)]
pub struct V2 {
pub x: i32,
pub y: i32,
}
#[repr(C)]
struct Buffer {
len: i32,
data: *mut V2,
}
#[no_mangle]
extern "C" fn generate_data() -> Buffer {
let mut buf = vec![V2 { x: 1, y: 0 }, V2 { x: 2, y: 0}].into_boxed_slice();
let data = buf.as_mut_ptr();
let len = buf.len() as i32;
std::mem::forget(buf);
Buffer { len, data }
}
#[no_mangle]
extern "C" fn free_buf(buf: Buffer) {
let s = unsafe { std::slice::from_raw_parts_mut(buf.data, buf.len as usize) };
let s = s.as_mut_ptr();
unsafe {
Box::from_raw(s);
}
}
b) Send the array through FFI callback function. User need to promise to not keep references, but dont need to call free.
#[no_mangle]
pub extern "C" fn context_get_byte_responses(callback: extern "stdcall" fn (*mut u8, i32)) -> bool {
let bytes: Vec<u8> = vec![];
callback(bytes.as_mut_ptr(), bytes.len() as i32);
true
}

Related

How to return Rust Vec of unknown size over FFI?

I have a Rust library that returns Vecs of size that cannot be predicted by the caller, and I'm looking for an elegant way to implement the FFI interface.
Since Vecs can't be passed over FFI, I understand I need to first return the length, and then fill a buffer with the contents.
Here's my current solution, which works by manually managing memory of the Vec and trusting the caller to
Compute the FfiVec
Create a buffer of appropriate size to copy into
Copy from the FfiVec, cleaning it up in the process
#[repr(C)]
pub struct FfiVec<T: Sized> {
ptr: *mut Vec<T>,
len: c_uint, // necessary for C process to know length of Rust Vec
}
impl<T: Sized> FfiVec<T> {
pub fn from_vec(v: Vec<T>) -> Self {
let len = v.len() as c_uint;
FfiVec {
ptr: Box::into_raw(Box::new(v)),
len,
}
}
pub fn drop(self) {
unsafe {
std::ptr::drop_in_place(self.ptr);
std::alloc::dealloc(self.ptr as *mut u8, Layout::new::<Vec<T>>())
}
}
}
#[no_mangle]
pub extern compute_my_vec() -> FfiVec<u8> {...}
#[no_mangle]
pub extern copy_from_my_vec(ffi_vec: FfiVec<u8>, buffer: *mut u8) -> {
let len = c_vec.len as usize;
let buffer_slice = unsafe { std::slice::from_raw_parts_mut(buffer, len) };
for (i, &item) in c_vec.slice().iter().take(len).enumerate() {
buffer_slice[i] = item;
}
c_vec.drop()
}
Is there a simpler way to do this? Or a common library that can do this for me?

Strange behaviour using println with raw pointer

I need a binary tree data structure in C, and there is already exist a binary tree implementation in Rust. So I decided to wrap that.
I made a C-compatible struct contains raw pointer to BTreeMap and add some methods that take a pointer to my wrapper struct.
The problem is in module test. The test is passed if I using my methods only, but whenever I put the println! macro between method calls, The test failed.
use std::collections::BTreeMap;
#[repr(C)]
pub struct my_btree {
btree: *mut BTreeMap<u64, u64>,
}
#[no_mangle]
pub extern "C" fn my_btree_new() -> *mut my_btree {
let boxed = Box::new(BTreeMap::<u64, u64>::new());
let mut ret = my_btree {
btree: Box::into_raw(boxed),
};
&mut ret as *mut my_btree
}
#[no_mangle]
pub extern "C" fn my_btree_insert(
btree: *mut my_btree,
key: u64,
val: u64,
) -> bool {
unsafe {
let mut boxed = Box::from_raw((*btree).btree);
let contains = (*boxed).contains_key(&key);
if contains {
return false;
}
(*boxed).insert(key, val);
println!("{:?}", boxed);
Box::into_raw(boxed);
return true;
}
}
#[no_mangle]
pub extern "C" fn my_btree_contains(btree: *mut my_btree, key: u64) -> bool {
unsafe {
let boxed = Box::from_raw((*btree).btree);
println!("{:?}", boxed);
let ret = (*boxed).contains_key(&key);
Box::into_raw(boxed);
ret
}
}
#[no_mangle]
pub extern "C" fn my_btree_free(btree: *mut my_btree) {
unsafe {
let _boxed = Box::from_raw((*btree).btree);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insert() {
let map = my_btree_new();
my_btree_insert(map, 1, 1);
my_btree_insert(map, 2, 2);
my_btree_insert(map, 3, 30);
let err = my_btree_contains(map, 1);
assert_eq!(err, true);
println!("???"); // If this line commented out, then test success without error.
my_btree_free(map);
}
}
when I run the test with below command,
$ cargo test -- --nocapture
In my terminal,
running 1 test
{1: 1}
{1: 1, 2: 2}
{1: 1, 2: 2, 3: 30}
{1: 1, 2: 2, 3: 30}
???
error: test failed, to rerun pass '--lib'
But if I comment out the println!("???"); then test pass without any error.
And if I put println between my_btree_insert calls, it failed in next call. It's weird. Why this happened?
You've got several issues.
In my_btree_new, you construct an instance of my_btree on the stack (ie. local to the function) and then return a pointer to it.
In my_btree_insert, you take your pointer, then construct a Box around it. Before returning, you deconstruct the Box so that the item won't be freed - but you also have an early return path that does not deconstruct the Box. Your test case does not exercise that code path, but I expect it would crash if it did.
Why does it only crash when you insert the println!? Simple - the extra function call(s) that are generated trash the area of the stack containing the my_btree.
Here are a few suggestions for fixing it up:
You do not really need the wrapper struct (at least for this basic example). But if you are going to have one, the whole struct should be on the heap, not just the BTree structure.
You don't need to box/unbox the pointer in every method; it is not adding value and is just increasing the chances you will forget to rebox it in some code path, resulting in a double-free crash. Only re-box it in the my_btree_free function.
You have made all these functions safe with the code inside wrapped in an unsafe block. That's not really correct - the compiler cannot verify that the pointer being supplied is correct, therefore the function is not safe (or putting it another way, a safe function should not crash regardless of the arguments you supply).
Here is a version that works:
use std::collections::BTreeMap;
#[repr(C)]
pub struct my_btree {
btree: BTreeMap<u64, u64>,
}
#[no_mangle]
pub extern "C" fn my_btree_new() -> *mut my_btree {
let boxed = Box::new(my_btree { btree: BTreeMap::<u64, u64>::new() } );
Box::into_raw(boxed)
}
#[no_mangle]
pub unsafe extern "C" fn my_btree_insert(
btree: *mut my_btree,
key: u64,
val: u64,
) -> bool {
let contains = (*btree).btree.contains_key(&key);
if contains {
return false;
}
(*btree).btree.insert(key, val);
return true;
}
#[no_mangle]
pub unsafe extern "C" fn my_btree_contains(btree: *mut my_btree, key: u64) -> bool {
(*btree).btree.contains_key(&key)
}
#[no_mangle]
pub unsafe extern "C" fn my_btree_free(btree: *mut my_btree) {
let _boxed = Box::from_raw(btree);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insert() {
let map = my_btree_new();
unsafe {
my_btree_insert(map, 1, 1);
my_btree_insert(map, 2, 2);
my_btree_insert(map, 3, 30);
let err = my_btree_contains(map, 1);
assert_eq!(err, true);
println!("???"); // If this line commented out, then test success without error.
my_btree_free(map);
}
}
}

How to fill Rust function pointer from C++

I want to call C++ from Rust. C++ then allocates and fills a buffer, then Rust uses it and deallocates. However, I'd like to deliver back the function pointer to deallocate the data. This is what I tried:
In Rust:
extern "C" {
pub fn openvpn_receive(
instance: *mut OpenVpnInstance,
size: *mut size_t,
deallocate: extern "C" fn(*mut u8),
) -> *mut u8;
}
fn main() {
let size: *mut size_t;
let deallocate = extern "C" fn(*mut u8);
let data: *mut u8 = openvpn_receive(self.instance, size, deallocate);
//use data
deallocate(data);
}
In C++:
uint8_t* openvpn_receive(size_t *size, void (*deallocate_function)(uint8_t *))
{
deallocate_function = &cpp_deallocate_u8;
uint8*t data = receive_data(size);
}
But the Rust code is not valid. How can I make such thing happen?
Maybe it will help You.
https://doc.rust-lang.org/std/keyword.extern.html
https://rust-embedded.github.io/book/interoperability/rust-with-c.html
C++ -> C -> Rust
use libc::{size_t, c_void};
#[repr(C)]
pub struct OpenVpnInstance();
//#[link(name = "your_c_library")]
extern "C" {
pub fn openvpn_receive(
instance: *mut OpenVpnInstance,
size: *mut size_t,
deallocate: *mut c_void,
) -> *mut u8;
}
pub fn my_callback(arg: *mut u8)
{
println!("CB!");
}
fn main()
{
let size: size_t = 42;
let instance = OpenVpnInstance{};
let dummy_arg: u8 = 42;
unsafe {
let cb = my_callback as *mut c_void;
let instance_ptr = &instance as *const _ as *mut OpenVpnInstance;
let arg_ptr = &dummy_arg as *const _ as *mut u8;
openvpn_receive(instance_ptr, size as *mut size_t, cb);
my_callback(arg_ptr)
}
}

How to get the next pointer?

I have a function implemented in C, and I want to write a function in Rust with the same interface. The function receives a pointer to the beginning of the array (win8_t *) and the length of the array. I need to be able to run through the array.
There must be a better way to get the next value, but now I can do this strange thing:
use std::mem;
pub extern "C" fn print_next(i: *const u8) {
let mut ii = unsafe { mem::transmute::<*const u8, i64>(i) };
ii += 1;
let iii = unsafe { mem::transmute::<i64, *const u8>(ii) };
let jj = unsafe { *iii };
println!("{}", jj); // jj is next value
}
As Shepmaster said, you probably need to provide the length of the slice.
Most of the time you're working with pointers, your function will be unsafe (because you usually need to dereference it at some point). It might be a good idea to mark them unsafe to delegate the safety responsibility to the caller.
Here are some examples using offset and from_raw_slice:
use std::mem;
use std::slice;
// unsafe!
pub extern "C" fn print_next(i: *const u8) {
let mut ii = unsafe { mem::transmute::<*const u8, i64>(i) };
ii += 1;
let iii = unsafe { mem::transmute::<i64, *const u8>(ii) };
let jj = unsafe { *iii };
println!("{}", jj); // jj is next value
}
// unsafe!
pub unsafe extern "C" fn print_next2(i: *const u8) {
let j = *i.offset(1);
println!("{}", j);
}
// (less but still ...) unsafe!
pub unsafe extern "C" fn print_next3(i: *const u8, len: usize) {
let slice = slice::from_raw_parts(i, len);
// we are not checking the size ... so it may panic!
println!("{}", slice[1]);
}
fn main() {
let a = [9u8, 4, 6, 7];
print_next(&a as *const u8);
unsafe {
print_next2(&a[1] as *const u8);
print_next3(&a[2] as *const u8, 2);
}
// what if I print something not in a??
print_next(&a[3] as *const u8); // BAD
unsafe {
print_next2(&a[3] as *const u8); // BAD
print_next3(&a[3] as *const u8, 2); // as bad as others, length is wrong
print_next3(&a[3] as *const u8, 1); // panic! out of bounds
}
}

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