问题
I have a rubygem with a native extension written in rust.
The native extension supports serializing its data-structure to JSON.
However, whilst I've confirmed it's generating JSON, the string is always empty on the ruby side.
Here's the ruby code:
module RustCuckooFilter
extend FFI::Library
ffi_lib 'libcuckoofilter_cabi'
class Instance < FFI::AutoPointer
def export(path)
RustCuckooFilter.export(self)
end
end
attach_function :export, :rcf_cuckoofilter_export, [Instance], :pointer
And the rust code
/// Exports the filter to a file
#[no_mangle]
pub extern "C" fn rcf_cuckoofilter_export(filter: *mut rcf_cuckoofilter) -> *const c_char {
let filter = unsafe { filter.as_mut() };
let serialized = serde_json::to_string(&filter.expect("Given rcf_cuckoofilter* is a null pointer").export()).unwrap();
let cstr = CString::new(serialized).expect("JSON was not a valid c string");
let ptr = cstr.as_ptr();
unsafe {
println!("{:#?}", ptr);
println!("{}", CStr::from_ptr(ptr).to_str().expect("validity"));
}
ptr
}
On the Rust side, the println!
use confirms that the pointer contains a JSON string.
By comparing the address it prints with the return value of #export
in ruby I can see that the same pointer is used.
However, calling get_bytes(0, 10)
on the pointer reveals that it starts with null bytes, and attempting to convert it to a string returns an empty string.
I suspect that it's getting zeroed out because the variables lifetime is over and I'm building in debug mode; however, I'm not clear what I'd need to change.
回答1:
Figured it out - I needed to use CString::into_raw
on the rust side to prevent it getting cleaned up.
来源:https://stackoverflow.com/questions/55173958/string-becomes-empty-passing-through-ffi-from-rust-to-ruby