Código de ejemplo a continuación
La parte de óxido:
#[no_mangle] pub extern fn call_c_function(value: i32, fun: fn(i32) -> i32) -> i32 { fun(value) }Y la parte C:
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; } Por supuesto, la segunda llamada de call_c_function . El compilador de Rust no se quejará del código no seguro dentro de call_c_function , porque desde el punto de vista de Rust, este código es seguro. Además, no está permitido simplemente escribir:
if !fun.is_null() { fun(value) } porque el tipo fun es fn(i32) -> i32 (no es un puntero).
Entonces, mi pregunta es, ¿cómo puedo proteger call_c_function contra la desreferencia de puntero NULL? ¿Hay alguna forma de verificar si la devolución de llamada pasada desde C no es válida?
¿Tal vez tengo que cambiar la definición de call_c_function ?
Puede usar Option<...> para representar punteros de función anulables. Es incorrecto tener un valor NULL para un valor de tipo fn(...) por lo que se requiere el contenedor de Option para casos como este.
Por ejemplo,
#[no_mangle] pub extern "C" fn call_c_function(value: i32, fun: Option<fn(i32) -> i32>) -> i32 { if let Some(f) = fun { f(value) } } Sin embargo, hay un punto extra: fun es una función de C, pero el tipo fn(...) es una función de Rust. No son directamente compatibles (por ejemplo, sus convenciones de llamadas difieren). Uno necesita usar el tipo extern "C" fn(...) (también conocido como extern fn(...) ) al interactuar con punteros de función C:
#[no_mangle] pub extern "C" fn call_c_function(value: i32, fun: Option<extern "C" fn(i32) -> i32>) -> i32 { if let Some(f) = fun { f(value) } }Puede comparar un puntero generado por un código no seguro con std::ptr::null()
p.ej
let pw = libc::getpwnam(username.as_ptr() as *const i8); if std::ptr::null() != pw ... null() en Linux es 0 as *const T No estoy seguro de si eso es universal.