How to correctly use a release of a sharable FFI struct?

What about adding another wrapper which implements Drop?

#[repr(C)]
struct Schema {
  destroy: Option<unsafe extern "C" fn(*mut Schema)>,
  ...
}

extern "C" {  fn some_external_function() -> *mut Schema; }

/// A Rust wrapper which manages a [`Schema`]'s lifetime and gives it
/// convenient methods or trait implementations.
struct SchemaHandle(*mut Schema);

impl Drop for SchemaHandle {
  fn drop(&mut self) {
    if let Some(destroy) = (*self.0).destroy {
      unsafe { destroy(self.0); }
    }
  }
}

fn main() {
  unsafe {
    let schema = some_external_function();
    let handle = SchemaHandle(schema);
    let shared = Arc::new(handle);
  }
}

Depending on the implementation of destroy() either you or the destroy() function will need to deallocate the top Schema's memory. If you need to implement it, just add a libc::free(self.0) at the very end of the Drop::drop() method.

1 Like