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)
}
}
Related
I'm trying to use bindings generated for cuBLAS using bindgen. Here's what my code looks like:
mod tests {
use super::*;
#[test]
pub fn alpha () {
let mut handle: cublasHandle_t;
let mut stat: cublasStatus_t;
let mut cudaStat: cudaError_t;
... some stuff
unsafe {
cudaStat = cudaMalloc(a.as_mut_ptr() as *mut *mut c_void, a.len() as u64);
cudaStat = cudaMalloc(b.as_mut_ptr() as *mut *mut c_void, b.len() as u64);
cudaStat = cudaMalloc(c.as_mut_ptr() as *mut *mut c_void, c.len() as u64);
stat = cublasCreate_v2(handle as *mut *mut cublasContext);
}
...some stuff
}
}
I get this error:
error: expected expression, found keyword `mut`
--> src/lib.rs:44:37
|
44 | stat = cublasCreate_v2(handle as *mut *mut cublasContext);
| ^^^ expected expression
error: could not compile `cublas-rs` due to previous error
NOTE: cublasHandle_t is a typedef for *mut cublasContext.
I've tried doing just &handle, *mut handle, etc but no dice.
cublasHandle_t is only supposed to be initialized by cublasCreate_v2.
Here's what things look like in bindings.rs:
// cublasContext struct we want to pass to cublasCreate_v2
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct cublasContext {
_unused: [u8; 0],
}
// alternative typedef used by cublas
pub type cublasHandle_t = *mut cublasContext;
// function to create a cublas handle
extern "C" {
pub fn cublasCreate_v2(handle: *mut cublasHandle_t) -> cublasStatus_t;
}
I've tried initializing it like this:
let mut handle: cublasHandle_t = *mut cublasContext { _unused: [] }; // no luck
let mut handle: cublasHandle_t = cublasContext { _unused: [] } as *mut cublasContext; // no
How do I call a function like this?
Actually, you probably want to just set handle to a null pointer to start with, since you say cublasCreate_v2 is supposed to create the handle.
mod tests {
use super::*;
pub fn alpha () {
// initialize with null pointer
let mut handle: cublasHandle_t = std::ptr::null_mut();
let mut stat: cublasStatus_t;
// ... some stuff
unsafe {
cudaStat = cudaMalloc(a.as_mut_ptr() as *mut *mut c_void, a.len() as u64);
cudaStat = cudaMalloc(b.as_mut_ptr() as *mut *mut c_void, b.len() as u64);
cudaStat = cudaMalloc(c.as_mut_ptr() as *mut *mut c_void, c.len() as u64);
// pass pointer to the pointer, using `&mut x`
stat = cublasCreate_v2(&mut handle);
}
// ...some stuff
}
}
You need to create the context as a variable first, before creating a pointer to it. To create a pointer to a value, you use &mut value, similar to &value in C.
mod tests {
use super::*;
pub fn alpha () {
let mut context = cublasContext { _unused: [] }; // create context
// get pointer to context, `&mut x` can be assigned to `*mut x`
let mut handle: cublasHandle_t = &mut context;
let mut stat: cublasStatus_t;
// ... some stuff
unsafe {
cudaStat = cudaMalloc(a.as_mut_ptr() as *mut *mut c_void, a.len() as u64);
cudaStat = cudaMalloc(b.as_mut_ptr() as *mut *mut c_void, b.len() as u64);
cudaStat = cudaMalloc(c.as_mut_ptr() as *mut *mut c_void, c.len() as u64);
// pass double-pointer, using `&mut x` again
stat = cublasCreate_v2(&mut handle);
}
// ...some stuff
}
}
You might want to add #[derive(Default)] to cublasContext, so you can do cublasContext::default() instead of needing to set up _unused.
There's the following line in C:
my_struct->ptr = (char*) data
where as you can see, my_struct has a ptr member of type char*
I have this on Rust:
struct MyStruct {
ptr: *mut libc::c_char
}
then I fill it like this:
unsafe{*my_struct}.ptr = Box::into_raw(my_data) as *mut libc::c_char;
unsafe{((*my_struct).ptr as *mut MyData).as_mut()}.unwrap();
but I'm getting either an unwrap panic on the line above. See that I acessed it immeidately after setting it, so no lifetime, out of scope problems for this data.
Here's the actual MyStruct:
https://github.com/mysql/mysql-server/blob/8.0/include/mysql/udf_registration_types.h#L69
I think the problem is resumed here:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=293ca891bedb9528ae840bcdf737777c
or in other words:
#[derive(Clone, Copy)]
struct MyStruct {
ptr: *mut libc::c_char
}
struct MyData{}
fn main() {
let my_struct = &mut MyStruct{
ptr: std::ptr::null_mut()
} as *mut MyStruct;
let my_data = Box::new(MyData{});
unsafe{*my_struct}.ptr = Box::into_raw(my_data) as *mut libc::c_char;
unsafe{((*my_struct).ptr as *mut MyData).as_mut()}.unwrap();
}
By doing unsafe{*my_struct}.ptr, you're copying *my_struct, then overwriting .ptr of that copy, which is why you're observing no change. Instead, write to (*my_struct).ptr:
unsafe {
(*my_struct).ptr = Box::into_raw(my_data) as *mut libc::c_char;
}
I am following up on Casting a borrowed reference with a lifetime to a raw pointer in Rust, which solved the wrong problem.
Please consider the following code:
extern crate jni;
extern crate ffi;
use jni::JNIEnv;
use jni::objects::JClass;
use jni::sys::{jint, jlong, jobject};
struct CameraAppEngine {
_env: *mut jni::sys::JNIEnv,
_width: i32,
_height: i32
}
impl CameraAppEngine {
pub fn new(_env: *mut jni::sys::JNIEnv, _width: i32, _height: i32) -> CameraAppEngine {
CameraAppEngine { _env, _width, _height }
}
pub fn create_camera_session(&mut self, surface: jobject) {
// error!
let window = ffi::ANativeWindow_fromSurface(self._env, surface);
}
}
fn app_engine_create(env: &JNIEnv, width: i32, height: i32) -> *mut CameraAppEngine {
let engine = CameraAppEngine::new(env.get_native_interface(), width, height);
Box::into_raw(Box::new(engine))
}
#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_createCamera(env: JNIEnv<'static>, _: JClass, width:jint, height:jint) -> jlong {
app_engine_create(&env, width, height) as jlong
}
#[no_mangle]
pub extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_onPreviewSurfaceCreated(_: JNIEnv, _: JClass, engine_ptr:jlong, surface:jobject) {
let mut app = unsafe { Box::from_raw(engine_ptr as *mut CameraAppEngine) };
app.create_camera_session(surface);
}
And in the ffi crate we have:
extern "C" {
pub fn ANativeWindow_fromSurface(env: *mut JNIEnv, surface: jobject) -> *mut ANativeWindow;
}
This results in:
error[E0308]: mismatched types
--> native_app/src/lib.rs:24:53
|
| let window = ffi::ANativeWindow_fromSurface(self._env, surface);
| ^^^^^^^^^ expected struct `ffi::JNINativeInterface`, found struct `jni::sys::JNINativeInterface_`
|
= note: expected raw pointer `*mut *const ffi::JNINativeInterface`
found raw pointer `*mut *const jni::sys::JNINativeInterface_`
error[E0308]: mismatched types
--> native_app/src/lib.rs:24:64
|
| let window = ffi::ANativeWindow_fromSurface(self._env, surface);
| ^^^^^^^ expected enum `std::ffi::c_void`, found enum `jni::sys::_jobject`
|
= note: expected raw pointer `*mut std::ffi::c_void`
found raw pointer `*mut jni::sys::_jobject`
The problem is that the JNIEnv type expected by ANativeWindow_fromSurface is actually unrelated to jni::sys::JNIEnv entirely.
It's defined in ffi like so:
pub type JNIEnv = *const JNINativeInterface;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct JNINativeInterface {
pub reserved0: *mut ::std::os::raw::c_void,
pub reserved1: *mut ::std::os::raw::c_void,
pub reserved2: *mut ::std::os::raw::c_void,
pub reserved3: *mut ::std::os::raw::c_void,
pub GetVersion: ::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv) -> jint>,
pub DefineClass: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut JNIEnv,
arg2: *const ::std::os::raw::c_char,
arg3: jobject,
arg4: *const jbyte,
arg5: jsize,
) -> jclass,
>,
pub FindClass: ::std::option::Option<
unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: *const ::std::os::raw::c_char) -> jclass,
>,
pub FromReflectedMethod:
::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jmethodID>,
pub FromReflectedField:
::std::option::Option<unsafe extern "C" fn(arg1: *mut JNIEnv, arg2: jobject) -> jfieldID>,
pub ToReflectedMethod: ::std::option::Option<
unsafe extern "C" fn(
arg1: *mut JNIEnv,
arg2: jclass,
arg3: jmethodID,
arg4: jboolean,
) -> jobject,
>
// etc...
}
Given the glue code shown in the example, how do I get a valid reference to ffi::JNIEnv so that I may pass it to the ANativeWindow_fromSurface method. Bonus points if you give advice on converting jni::sys::jobject to *mut std::os::raw::c_void (lifetime concerns, null pointers, etc.).
Full source to ffi definitions
Here is the basic helloworld implementation I used to prove the concept in the accepted answer:
use std::ffi::{CString, CStr};
use std::os::raw::{c_char};
/// Expose the JNI interface for android below
#[cfg(target_os="android")]
#[allow(non_snake_case)]
pub mod android {
extern crate ffi;
use super::*;
use self::ffi::{JNIEnv, jclass, jstring, jlong};
#[derive(Debug)]
struct AppEngine {
greeting: *mut c_char
}
unsafe fn rust_greeting(app: *mut AppEngine) -> *mut c_char {
let app = Box::from_raw(app);
app.greeting
}
/// Constructs an AppEngine object.
fn rust_engine_create(to: *const c_char) -> *mut AppEngine {
let c_str = unsafe { CStr::from_ptr(to) };
let recipient = match c_str.to_str() {
Err(_) => "there",
Ok(string) => string,
};
let greeting = CString::new("Hello ".to_owned() + recipient).unwrap().into_raw();
let app = AppEngine{greeting: greeting};
Box::into_raw(Box::new(app))
}
/// Destroys an AppEngine object previously constructed using `rust_engine_create()`.
unsafe fn rust_engine_destroy(app: *mut AppEngine) {
drop(Box::from_raw(app))
}
#[no_mangle]
pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_greeting(env: &mut JNIEnv, _: jclass, app_ptr: jlong) -> jstring {
let app = app_ptr as *mut AppEngine;
let new_string = env.as_ref().unwrap().NewStringUTF.unwrap();
new_string(env, rust_greeting(app))
}
#[no_mangle]
pub unsafe extern fn Java_io_waweb_cartoonifyit_MainActivity_createNativeApp(env: &mut JNIEnv, _: jclass, java_pattern: jstring) -> jlong {
let get_string_chars = env.as_ref().unwrap().GetStringChars.unwrap();
let is_copy = 0 as *mut u8;
rust_engine_create(get_string_chars(env, java_pattern, is_copy) as *const c_char ) as jlong
}
#[no_mangle]
pub unsafe extern "C" fn Java_io_waweb_cartoonifyit_MainActivity_destroyNativeApp(_: JNIEnv, _: jclass, app_ptr: jlong) {
let app = app_ptr as *mut AppEngine;
rust_engine_destroy(app)
}
}
This is just a proof of concept. More care should be taken when casting raw pointers about. Also see notes about Box::leak in the accepted answer.
A JNIEnv is a pointer to a struct used for communication between Java and native code. This communication ABI is implemented by pretty much every JVM(and android). There are multiple versions of the aforementioned structs, which is what the GetVersion field is for.
It seems to me that you are using an external jni crate along with your own ffi crate generated from this wrapper. I would expect your ffi crate to be the most correct since it is using android headers, instead of the standard JVM headers which a most likely being used by the jni crate.
One last note Box::from_raw(engine_ptr as *mut CameraAppEngine), creates a box which will free the memory located at engine_ptr. This is likely not what you want. Consider using Box::leak to leak the created Box and avoid use after frees.
Let's say I have a C function:
void func(char *buf, unsigned int *len);
To call it in Rust, I declared:
pub fn func(buf: *mut ::std::os::raw::c_char, len: *mut ::std::os::raw::c_uint) {
unimplemented!()
}
Then I wrote another wrapper:
pub fn another_func() -> String {
let mut capacity: u32 = 256;
let mut vec = Vec::with_capacity(capacity as usize);
unsafe {
func(vec.as_ptr() as *mut c_char, &capacity as *mut c_uint)
};
String::from_utf8(vec).unwrap();
unimplemented!()
}
But the compiler told me:
error[E0606]: casting `&u32` as `*mut u32` is invalid
--> src/main.rs:...:28
|
307 | &capacity as *mut c_uint)
Why can't I cast capacity into *mut c_unit?
It turns out I have to make the reference mutable.
func(vec.as_ptr() as *mut c_char, &mut capacity as *mut c_uint)
Passing just an array seems to work fine:
fn set_zero<'a>(u: &'a u32, ms: &mut [Option<&'a u32>; 4]) {
ms[0] = Some(u);
}
I'm trying to wrap C callback function which is passed a void *
so I'm using std::any::Any instead of an array:
fn set_zero<'a>(u: &'a u32, ma: &mut Any) {
if let Some(ms) = ma.downcast_mut::<[Option<&'a u32>; 4]>() {
ms[0] = Some(u);
}
}
This causes an error related to lifetimes:
error[E0477]: the type `[std::option::Option<&'a u32>; 4]`
does not fulfill the required lifetime
--> option.rs:18:26
|
18 | if let Some(ms) = ma.downcast_mut::<[Option<&'a u32>; 4]>() {
| ^^^^^^^^^^^^
|
= note: type must outlive the static lifetime
How can I fix this? What documentation should read to understand the error better?
UPDATE: more detailed background:
An contrived C prototype is - foo.c:
#include <stdint.h>
typedef int (*cb_t)(const uint32_t *obj, void *arg);
int32_t cb_run(uint32_t const objs[], uint32_t len, cb_t cb, void *arg)
{
int i;
for (i = 0; i < len; i++)
if (cb(&objs[i], arg) < 0)
return -1;
return 0;
}
Then, I tried to wrap by using Any:
extern crate libc;
use libc::{c_int, size_t, c_void};
use std::any::Any;
type CbT = extern "C" fn(obj: *const u32, arg: *mut c_void) -> c_int;
extern { fn cb_run(objs: *const u32, len: size_t, cb: CbT, arg: *mut c_void) -> c_int; }
type Cb = fn(obj: &u32, arg: &mut Any) -> i32;
struct CbData <'a> {
cb: Cb,
arg: &'a mut Any,
}
extern fn rust_cb(obj: *const u32, arg: *mut c_void) -> c_int {
unsafe {
let s = &mut *(arg as *mut CbData);
(s.cb)(&*obj, s.arg)
}
}
fn cb_run_rs(objs: &[u32], cb: Cb, arg: &mut Any) -> i32 {
let mut arg = &mut CbData{ cb: cb, arg: arg } ;
unsafe { cb_run(objs.as_ptr() as *const u32, objs.len() as size_t,
rust_cb, arg as *mut _ as *mut c_void) as i32 }
}
//// the above is lib, the below is bin
// set_zero() in the above
fn my_cb<'a>(obj: &'a u32, arg: &mut Any) -> i32 {
if let Some(data) = arg.downcast_mut::<[Option<&'a u32>; 4]>() {
data[0] = Some(obj);
}
0
}
fn main() {
let objs = [0u32, 1, 2, 3];
let mut arg = [None; 4];
println!("pre : {:?}", arg);
cb_run_rs(&objs, my_cb, &mut arg);
println!("post : {:?}", arg);
}
And it causes note: type must outlive the static lifetime.
How can I handle this kind of void * in good manner without unsafe from library user?
I can only tell it seems to work. main.rs
extern crate libc;
use libc::{c_int, size_t, c_void};
type CbT = extern "C" fn(obj: *const u32, arg: *mut c_void) -> c_int;
extern { fn cb_run(objs: *const u32, len: size_t, cb: CbT, arg: *mut c_void) -> c_int; }
type Cb <'a, T: ?Sized> = fn(obj: &'a u32, arg: &mut T) -> i32;
struct CbData <'a, 'b, T: 'a + 'b + ?Sized> {
cb: Cb<'a, T>,
arg: &'b mut T,
}
extern fn rust_cb<T: ?Sized>(obj: *const u32, arg: *mut c_void) -> c_int {
unsafe {
let s = &mut *(arg as *mut CbData<T>);
(s.cb)(&*obj, s.arg)
}
}
fn cb_run_rs<'a, 'b, T: 'a + ?Sized>(objs: &[u32], cb: Cb<'a, T>, arg: &'b mut T) -> i32 {
let mut arg = &mut CbData{ cb: cb, arg: arg } ;
unsafe { cb_run(objs.as_ptr() as *const u32, objs.len() as size_t,
rust_cb::<T>, arg as *mut _ as *mut c_void) as i32 }
}
//// the above is lib, the below is bin
fn my_cb<'a>(obj: &'a u32, arg: &mut [Option<&'a u32>]) -> i32 {
arg[*obj as usize] = Some(obj);
0
}
fn main() {
let objs = [0u32, 1, 2, 3];
let mut arg = [None; 4];
println!("pre : {:?}", arg);
cb_run_rs(&objs, my_cb, &mut arg);
println!("post : {:?}", arg);
}
FYI build.rs:
extern crate gcc;
fn main() {
gcc::compile_library("libfoo.a", &["src/foo.c"]);
}
Cargo.toml:
[package]
name = "sof"
version = "0.1.0"
authors = ["author#example.com"]
build = "build.rs"
[build-dependencies]
gcc = "0.3"
[dependencies]
libc = "0.2"