Safety of saving &'lifetime C-struct in FFI Binding

I'm writing a FFI wrapper to a C library outside my control. (FFmpeg in this case, but I think the question is more general).

I have this situation:

struct OwnedStruct {
   c_lib_ptr: *mut CLibStruct,

impl Drop for OwnedStruct {
  fn drop(&mut self) { unsafe { c_lib_free(self.c_lib_ptr) }; }

impl<'a> OwnedStruct {
  fn get_inner(&'a self) -> InnerStruct<'a> {
    InnerStruct( unsafe { (*self.c_lib_ptr).inner }, PhantomData)

struct InnerStruct<'a>(*const CLibInner, PhantomData<&'a CLibInner>);

I'm using InnerStruct mostly for accessors to the inner data. First, it striked me that this must be a common pattern, and went looking for a data-structure to augment a pointer with a lifetime. Found none (in std). It then hit me, that I should be able to simply define InnerStruct as (&'a CLibInner), but it got me thinking, that I cannot guarantee that there are no mutations being done on the C-side of the interface for the Lifetime of InnerStruct. The C-lib uses inner threads in some cases, so even for a highly short-lived '&CLibInner', I can't really guarantee concurrent non-mutation.

What's the right thing to do here? From what I understand, the "one writer or many readers"-rule does not apply to pointers, only to references? Is my original solution as good as can be? In that case, it still seems like a pattern that should be fairly common in bindings? Are there any "canonical" crates that provide the helper I were looking for? (I need this in more than one place).

Unlike references, raw pointers have no aliasing requirements, so mutation while a *const CLibInner exists is allowed. That said, data races are still undefined behaviour, so watch out for threads.


This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.