I have a library I need to use, which exposes a method that sets some callback. But that method takes a void*
. That is later recasted into a void(*)(int)
(funtion that takes an int).
Something like:
#include "stdio.h"
typedef void (*callback)(int i);
void call_it(void* f) {
callback fn = (callback) f;
fn(10);
}
Then, I need to pass that callback from rust
:
use std::ffi::c_void;
#[link(name = "demo", kind = "static")]
extern "C" {
fn call_it(f: *mut c_void);
}
fn p(n: isize) {
println!("{n}");
}
fn run<F: FnMut(isize) 'static>(mut f: F) {
let mut cb: &mut dyn FnMut(isize) = &mut f;
let ptr = &mut cb as *mut &mut _ as *mut c_void;
unsafe { call_it(ptr) };
}
fn main() {
run(p);
}
Which runs into a SEGFAULT
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
I have already checked some questions/answers, like:
How do I create a Rust callback function to pass to a FFI function?
How do I convert a Rust closure to a C-style callback?
Calling Rust function with function parameter from C results in SegFault
And couldn't get my head around it.
I cannot change the C
part, so what can I do from the rust
side?
CodePudding user response:
You may consider follow the example Callbacks from C code to Rust functions.
The requirement for this is that the callback function is marked as extern with the correct calling convention to make it callable from C code.
Just turn your Rust code into:
use std::ffi::c_void;
#[link(name = "demo", kind = "static")]
extern "C" {
fn call_it(f: *mut c_void);
}
extern "C" fn p(n: isize) {
println!("{n}");
}
fn run(f: extern "C" fn(isize)) {
unsafe { call_it(f as *mut c_void) };
}
fn main() {
run(p);
}