I'm trying to pass an array of strings from a rust library to a nodejs program via FFI. I followed an example from Create struct in C/Rust code for Node-FFI but can't quite get it to work. It works fine with a single element in the array, but if I add 2 elements I get a Segmentation Fault trying to read the second element.
Rust code:
#[repr(C)]
pub struct Config {
pub value: String,
}
#[repr(C)]
pub struct State {
pub configs: *mut Config,
pub num_configs: usize,
}
#[no_mangle]
pub extern "C" fn fetchData() -> *mut State {
let mut ffi_items: Vec<Config> = vec![];
ffi_items.push(Config {
value: String::from("Hello"),
});
ffi_items.push(Config {
value: String::from("World"),
});
return Box::into_raw(Box::new(State {
configs: Box::into_raw(ffi_items.into_boxed_slice()) as *mut Config,
num_configs: 2,
}))
}
NodeJS code:
const ref = require('ref-napi')
const ffi = require('ffi-napi')
const path = require('path')
const ArrayType = require('ref-array-di')(ref)
const StructType = require('ref-struct-di')(ref)
console.log('NODE: Running...')
const Config = StructType({
value: ref.types.CString,
});
const State = StructType({
configs: ArrayType(Config),
num_configs: ref.types.size_t,
})
const StatePtr = ref.refType(State);
const libPath = path.join(__dirname, '../target/release/libfetch.dylib')
const lib = ffi.Library(libPath, {
fetchData: [ StatePtr, [] ]
});
const dataRef = lib.fetchData()
const data = dataRef.deref()
data.configs.length = data.num_configs
console.log(`NODE: data.configs.length = ${data.configs.length}`)
console.log(`NODE: data[0] = ${data.configs[0]?.value}`)
console.log(`NODE: data[1] = ${data.configs[1]?.value}`)
Console output:
$ node src/index.js
NODE: Running...
NODE: data.configs.length = 0
NODE: data[0] = Hello
Segmentation fault: 11
Versions:
$ rustc --version
rustc 1.59.0 (9d1b2106e 2022-02-23)
$ node -v
v16.15.0
Running this on mac os 12.3.1