节点FFI包装函数在同步使用时失败,但异步工作

时间:2016-10-09 23:01:39

标签: c node.js asynchronous rust node-ffi

我尝试使用Node FFI包装Rust库(公开C API)。我有以下代码包装两个函数。一个是"构造函数"返回一个指针。另一个接受一个指针并返回C字符串。

var libcomm = ffi.Library('lib/c_api/target/debug/libcomm', {
  'comm_address_for_content': ['pointer', ['string']],
  'comm_address_to_str': ['string', ['pointer']]
});

当我使用comm_address_to_str的异步调用时,响应是正确的。但是,当我尝试使用同步样式调用该函数时,它会返回垃圾,或者很少返回正确的结果。以下nodeunit测试练习场景:

const comm = require("../").libcomm;

exports.testAddressForContent = function (test) {
  const ptr = comm.comm_address_for_content('test');

  const result = comm.comm_address_to_str(ptr);
  test.equal(result, 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'); // always fails
  console.log('sync', result); // random garbage

  comm.comm_address_to_str.async(ptr, function(err, result) {
    test.equal(result, 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'); // always passes
    console.log('async', result); // 'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3'
    test.done();
  });
}

我无法弄清楚导致这种情况的原因,但我需要能够使用同步调用方式。我正在包装的Rust库的C API是here

1 个答案:

答案 0 :(得分:3)

我担心这个问题来自comm库,特别是comm_address_to_str函数:

#[no_mangle]
pub extern "C" fn comm_address_to_str(address: *const Address) -> *const c_char {
    let string = unsafe { *address }.to_str();
    CString::new(string).unwrap().as_ptr()
}

documentation of CString::as_ptr特别指出了这种模式:

use std::ffi::{CString};

let ptr = CString::new("Hello").unwrap().as_ptr();
unsafe {
    // `ptr` is dangling
    *ptr;
}

在最后一行创建的CString在将指针指向其内部后立即被破坏,导致悬空指针。

您正在使用的comm库需要修复,也可能值得审核其他函数。

这里的修复是泄漏CString,然后提供另一个用泄漏指针调用的函数,它将负责释放它。