Ideomatic Rust to storing/freeing externally allocated memory as a ref

An external C library allocates/frees memory via FFI. My rust code is a thin wrapper layer called by C, and allows other Rust developers to write safe Rust code without dealing with FFI from C. My layer needs to hold a reference to C-allocated object and do the Drop when requested by C code to cleanup. What would be the idiomatic way to store a reference to that struct and later free it in this case?

P.S. I am writing an FFI layer to allow safe Rust plugins to Varnish (large C program). Varnish calls my wrapper layer, which needs to restore context on each callback from some *void pointers before passing them to user Rust code. Sometimes the callback is to clean up resources – so I must restore context, perform drop on user’s T, followed by a C-call to free on the FFI C struct that held a pointer to T.

// Code generated by bindgen, from a C header file
#[repr(C)]
pub struct c_object {
    // Here I store a pointer to T - a Rust-allocated user obj
    pub user_obj: *mut ::std::ffi::c_void,
}

extern "C" {
    pub fn allocate_obj() -> *const c_object;
    pub fn free_obj(obj: *mut *const c_object);  // double-ref to set my ptr to NULL
}


// Safe Rust wrapper I need to design
// lifetime tied to some context object not specified here
struct Wrapper<'a> {
    // storing it as a reference to use Rust's ref checks
    // and avoid null-ref checks on each access
    obj: &'a c_object,
}

impl<'a> Wrapper<'a> {
    fn from_ptr(ptr: *const c_object) -> Self {
        Wrapper {
            // Asserting that the pointer is not null just once
            obj: ptr.as_ref().unwrap(),
        }
    }
}

impl Drop for Wrapper<'_> {
    fn drop(&mut self) {
        // How to call free_obj() here?
        // I need to pass a double-ref to set my ptr to NULL
        // Essentially after this drop Wrapper instance content is undefined?
    }
}

10

There are a couple of architectural decisions in your code that I would change:

  • Wrapper should not have a lifetime. It owns its value, and doesn’t depend on anything external. This should be obvious when thinking about the fact that its destructor destroys everything it depends on, nothing external has to be ‘given back’. Be aware that lifetimes don’t keep anything alive, they are just a way for the compiler to track dependencies. And Wrapper doesn’t depend on anything, everything it contains is owned by itself.
  • Wrapper::from_ptr absolutely needs to be unsafe, as there’s no sound way of implementing it without making unsafe assumptions. Read this for more information about soundness.
  • Do not use a reference. Like 'a, a reference is for storing a dependency to something owned, and we are the owner ourselves. Instead, us a raw pointer directly. Your situation is exactly what raw pointers are for.

All of that said, here’s some code that demonstrates how working code would look like:

// Code generated by bindgen, from a C header file
#[repr(C)]
pub struct c_object {
    // some fields
    x: core::ffi::c_uint,
}

extern "C" {
    pub fn allocate_obj() -> *const c_object;
    pub fn free_obj(obj: *mut *const c_object); // double-ref to set my ptr to NULL
}

// Dummy implementation for demo purposes
pub mod dummy_c_impls {
    use super::c_object;

    #[no_mangle]
    pub extern "C" fn allocate_obj() -> *const c_object {
        let ptr = Box::into_raw(Box::new(c_object { x: 42 }));
        println!("Allocate {:?}", ptr);
        ptr
    }
    #[no_mangle]
    pub extern "C" fn free_obj(obj: *mut *const c_object) {
        if let Some(obj) = unsafe { obj.as_mut() } {
            let mut ptr = std::ptr::null();
            std::mem::swap(obj, &mut ptr);

            if !ptr.is_null() {
                println!("Free {:?}", ptr);
                unsafe {
                    std::mem::drop(Box::from_raw(ptr as *mut c_object));
                }
            }
        }
    }
}

// Define Wrapper in a mod to prevent other objects from modifying ptr
mod wrapper {
    use super::{c_object, free_obj};

    // Safe Rust wrapper I need to design
    // lifetime tied to some context object not specified here
    pub struct Wrapper {
        // storing it as a reference to use Rust's ref checks
        // and avoid null-ref checks on each access
        ptr: *const c_object,
    }

    impl Wrapper {
        // Absolutely needs unsafe here, as there's not way of
        // implementing this function without unsafe assumptions
        pub unsafe fn from_ptr(ptr: *const c_object) -> Self {
            Self { ptr }
        }
    }

    impl Drop for Wrapper {
        fn drop(&mut self) {
            unsafe {
                free_obj(&mut self.ptr);
            }
        }
    }

    impl core::ops::Deref for Wrapper {
        type Target = c_object;

        fn deref(&self) -> &Self::Target {
            unsafe { self.ptr.as_ref() }.unwrap()
        }
    }
}

fn main() {
    use wrapper::Wrapper;

    let value = unsafe { Wrapper::from_ptr(allocate_obj()) };
    println!("{}", value.x);
}
Allocate 0x2681b09aef0
42
Free 0x2681b09aef0

6

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật