Daniel Heath
Daniel Heath

Reputation: 414

String becomes empty passing through FFI from rust to ruby

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.

Upvotes: 1

Views: 364

Answers (1)

Daniel Heath
Daniel Heath

Reputation: 414

Figured it out - I needed to use CString::into_raw on the rust side to prevent it getting cleaned up.

Upvotes: 2

Related Questions