我正在学习Rust并尝试使用FFI回调。我写了一个库,执行以下操作:
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