Home > Back-end >  Function callback from c using void*
Function callback from c using void*

Time:09-30

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);
}

  • Related