FFI回调和段错误

时间:2018-06-18 03:45:52

标签: rust ffi

我正在学习Rust并尝试使用FFI回调。我写了一个库,执行以下操作:

  • 初始化C数据结构。
  • 为此数据结构初始化包装器Rust结构。构造函数需要一个函数指针,即回调test_cb

用法如下:

let test_cb = move |n: i32| n * 2;
let mut _test_worker = new(test_cb);

这会在C端存储一个指向Rust数据结构的指针,反之亦然:在Rust中有一个指向C结构的指针:

pub struct Worker {
    ptr: WorkerPtr,        // Pointer to the C data structure
    cb: fn(i32) -> i32,    // Callback function
}

struct WorkerPtr(NonNull<worker>);
unsafe impl marker::Send for WorkerPtr {}
struct worker_s {
    void* rust_object;  // Pointer to the Rust data structure
};

C调用Rust指示Rust结构指针,Rust取消引用指针并调用它上面的方法:Worker.trigger_callback,结果被发送回C世界:

#[no_mangle]
pub extern "C" fn rust_callback(w: *mut Worker, raw_n: c_int) -> c_int {
    let n = raw_n as i32;
    println!("rust_callback: {}", n);
    unsafe {
        let out = (*w).trigger_callback(n);
        out as c_int
    }
}

一切正常,Rust对象中的方法被成功调用,正如预期的那样,程序输出如下所示(遵循上面显示的实现):

worker_new: worker = 0x7f9834d000c0
worker_set_rust_object: worker = 0x7f9834d000c0 rust_object = 0x10ca21000
trigger_callback: worker = 0x7f9834d000c0 rust_object = 0x10ca21000
rust_callback: 100
trigger_callback: 100
got: 200

在我的实际用例中,我正在使用字节库,我的回调是fn(bytes::Bytes) -> bytes::Bytes。我的测试运行正常并且Worker::trigger_callback被成功调用,但在某些情况下,我在调用存储在结构(self.cb/Worker.cb)中的函数指针时遇到分段错误和EXC_BAD_ACCESS。在Rust方面,我使用的是单线程。我还可以确认bytes对象是正确的,我甚至可以使用bytes.len()打印它的长度,唯一的问题是self.cb/Worker.cb调用。

我一直在尝试调试并找不到运气的原因,所以我正在寻找有关此方法的反馈等。完整的代码可用here

当多个线程(在C端)尝试同时访问回调函数指针时,是否会出现此问题?你会如何调试这个?

更新:我已经使用lldb调试了这个并想出了这个,函数指针有问题:

self.cb = 0x736a73742e
Process 32896 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x736a73742e)
    frame #0: 0x000000736a73742e
error: memory read failed for 0x736a737400

0 个答案:

没有答案