【问题标题】:How to check if function pointer passed from C is non-NULL如何检查从C传递的函数指针是否为非NULL
【发布时间】:2015-07-17 17:05:05
【问题描述】:

下面的示例代码

锈部分:

#[no_mangle]
pub extern fn call_c_function(value: i32, fun: fn(i32) -> i32) -> i32 {
    fun(value)
}

还有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;
}

call_c_function 的第二次调用当然会崩溃。 Rust 编译器不会抱怨 call_c_function 中的不安全代码,因为从 rust 的角度来看,这段代码是安全的。也不能简单写:

if !fun.is_null() {
    fun(value)
}

因为fun 类型是fn(i32) -> i32(它不是指针)。

所以我的问题是,如何保护 call_c_function 免受 NULL 指针取消引用?有什么方法可以检查从 C 传递的回调是否无效?

也许我必须更改call_c_function 的定义?

【问题讨论】:

  • 是的,只要检查 fun == NULL。或者为零,如果 NULL 不是生锈的东西。请注意,我不太了解 rust,但这就是您在 C 中的做法。
  • @Adrian Thx,这就是我要找的东西!

标签: c rust ffi


【解决方案1】:

您可以使用Option<...> 来表示可为空的函数指针。 fn(...) 类型的值具有 NULL 值是不正确的,因此此类情况需要 Option 包装器。

例如,

#[no_mangle]
pub extern "C" fn call_c_function(value: i32, fun: Option<fn(i32) -> i32>) -> i32 {
    if let Some(f) = fun {
        f(value)
    }
}

但是,还有一点:fun 是一个 C 函数,但类型 fn(...) 是一个 Rust 函数。它们不是直接兼容的(例如它们的调用约定不同)。在与 C 函数指针交互时需要使用 extern "C" fn(...)(又名 extern fn(...))类型:

#[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)
    }
}

【讨论】:

    【解决方案2】:

    您可以将不安全代码生成的指针与std::ptr::null()进行比较

    例如

    let pw = libc::getpwnam(username.as_ptr() as *const i8);
    if std::ptr::null() != pw ...
    

    null() 在 Linux 上是 0 as *const T 我不确定这是否通用。

    【讨论】:

    • 这不适用于 function 指针,因为 huon 的回答解释说,这些指针不可为空。
    猜你喜欢
    • 2011-09-05
    • 1970-01-01
    • 2013-08-20
    • 1970-01-01
    • 2015-02-07
    • 1970-01-01
    • 1970-01-01
    • 2011-12-23
    • 1970-01-01
    相关资源
    最近更新 更多