Example code below
The Rust part:
#[no_mangle]
pub extern fn call_c_function(value: i32, fun: fn(i32) -> i32) -> i32 {
fun(value)
}
And the C part:
int32_t call_c_function(int32_t value, int32_t (*fun)(int32_t));
int32_t triple(int32_t x)
{
return x*3;
}
int main(int argc, char *argv[])
{
int32_t value = 3;
int32_t result = call_c_function(value, triple);
printf("%d tripled is %d\n", value, result);
call_c_function(0, NULL); // Crash here
return EXIT_SUCCESS;
}
Of course second call of call_c_function
will crash.
Rust compiler will not complain about unsafe code inside call_c_function
, because from rust point of view this code is safe. Also it's not allowed to simply write:
if !fun.is_null() {
fun(value)
}
because fun
type is fn(i32) -> i32
(it's not a pointer).
So my question is, how I can protect call_c_function
against NULL pointer dereference? Is there any way to check if callback passed from C is not valid?
Maybe I have to change call_c_function
definition?
You can use
Option<...>
to represent nullable function pointers. It is incorrect to have a NULL value for a value of typefn(...)
so theOption
wrapper is required for cases like this.For example,
However, there's on extra point:
fun
is a C function, but the typefn(...)
is a Rust function. They're not directly compatible (e.g. their calling conventions differ), one needs to be using theextern "C" fn(...)
(akaextern fn(...)
) type when interacting with C function pointers: