I am trying to pass user data through a SAFE FFI function and re-use the data, but I can’t get it to work reliably. This is pretty specific code but it might not be about the details. Perhaps I am misunderstanding how the user data is supposed to work.
Basically, I am trying to move a parameter to the FFI and re-construct it in the callback the FFI calls for me.
use ffi_utils::FfiResult;
use neon::prelude::*;
use safe_app::App;
use safe_app::test_utils::create_auth_req;
use safe_core::btree_set;
use safe_core::ipc::Permission;
use std::collections::HashMap;
use std::ffi::CString;
use std::ffi::CStr;
use std::os::raw::c_void;
fn app_pub_enc_key(mut cx: FunctionContext) -> JsResult<JsUndefined> {
// Turn JS array buffer into App pointer
let app = cx.argument::<JsArrayBuffer>(0)?;
let app = cx.borrow(&app, |data| { data.as_slice::<u8>() });
let app = u64::from_ne_bytes([app[0], app[1], app[2], app[3], app[4], app[5], app[6], app[7]]) as *const App;
// Prevent dropping context, get pointer.
let cx = Box::new(cx);
let cx = Box::into_raw(cx) as *mut c_void;
dbg!(cx); // check if pointer is same on the other end
unsafe {
safe_app::ffi::crypto::app_pub_enc_key(app, cx, o_cb);
}
extern "C" fn o_cb(
user_data: *mut c_void,
error: *const FfiResult,
public_key_h: safe_app::ffi::object_cache::EncryptPubKeyHandle
) {
// Construct the construct again
let mut cx: Box<FunctionContext> = unsafe { Box::from_raw(user_data as *mut _) };
dbg!(user_data); // Pointer is same as on other side! Woohoo!
dbg!(cx.len()); // Sometimes correct, sometimes gibberish
// SEGFAULT!!
let f = cx.argument::<JsFunction>(1).unwrap();
}
Ok(JsUndefined::new())
}
Perhaps @nbaksalyar, @marcin or @Fraser could spot in a second what is wrong with this. If not, don’t worry, this is a very specific question and it’s probably because of my incompetence with Rust. I’ve spent a fair amount trying to get it to work, but my last resort for now is reaching out to some people that have more specific knowledge about Rust and FFI.
To explain a bit about the context of above code. I’m learning Rust and thought I’d try creating a Node.js addon that is a binding to safe_app::ffi
. This is done with Neon.
The mechanism I used above does work with another function when I test it. But I think it’s because I’m lucky the memory is not overwritten or something (safe_app_node/native/src/lib.rs at master · b-zee/safe_app_node · GitHub). So, basically I have two functions made, both using the same mechanism to pass the context via FFI to the callback.
Running the function above from Node.js gives something likes this now:
[src/lib.rs:35] cx = 0x0000561cad3b34f0 # }
[src/lib.rs:47] user_data = 0x0000561cad3b34f0 # } same!
[src/lib.rs:48] cx.len() = -1388704320 # Sometimes correctly prints 2
Segmentation fault (core dumped)