2016-10-09 50 views
1

我試圖用節點FFI包裝Rust庫(顯示C API)。我有以下代碼包裝兩個函數。一個是返回指針的「構造函數」。另一個接受一個指針並返回C字符串。節點FFI包裝功能在同步使用時失敗,但異步工作

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

回答

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,然後提供了另一種功能與泄露的指針,該指針將釋放它的保健被調用。

+0

謝謝!我想我應該注意到,我是這個上游'comm'庫的作者。它看起來像在使用'std :: mem :: forget(string)'之前返回'const * char'指向它確實解決了問題。 – Zac

+2

@Zac:不客氣:)我會注意到,通常你應該泄漏'CString'實例,而不是'string'。您可能想要在valgrind下運行您的Rust測試,以提前發現這些問題。 –

+2

請參閱[在FFI綜合版中返回字符串](http://jakegoulding.com/rust-ffi-omnibus/string_return/)。 – Shepmaster