FFI: how check if a raw pointer is valid or not

I'm new to rust and I want to implement a rust lib called by a c program.

The problem is how to check if the raw pointer passed in function parse is valid? because it may be dropped already by free_parser, and it will cause crash in this case.

#[no_mangle]
pub extern fn create_parser() -> *mut Parser {
   // let parser =  create a parser in some way ...
   let raw_pointer = unsafe { transmute(Box::new(parser)) };
   raw_pointer
}

#[no_mangle]
pub extern fn parse(ptr: *mut Parser, text: *const c_char) -> *mut c_char {
    let mut parser = unsafe { &mut *ptr };
    //   how to check the parser here before use it?
    // to do something with the parser & text,  and finally return result as c_char
    //...
}

#[no_mangle]
pub extern fn free_parser(ptr: *mut Parser) {
    if !ptr.is_null() {
        let _: Box<Parser> = unsafe { transmute(ptr) };
    }
}

thanks!

1 Like

There is no way to know if the pointer has been freed. The caller of your functions must ensure not to call parse if free_parser has been called.

Note that transmuting Box is not safe, as its memory representation is not specified. You must use into_raw() to get the raw pointer and use from_raw to construct the box back when you want to drop it.

3 Likes
  1. Avoid using transmute, because it silently allows nonsensical conversions.
  2. Definitely don't use transmute for pointers. It's never needed for pointers, because you can convert pointers and references using as.
  3. Don't even use as, because there's Box::into_raw() and Box::from_raw() that does the right thing for FFI.
4 Likes

No need to pass a pointer if it can't be read in other code. Just use some ID and store the structure in either static or thread local. (Few alternate ways possible too.)

1 Like

Can any ask for some specifics? I know about thread local but whenever someone mentions "global mutable" it's like a heresy has been spoken. :wink:

So, how do you do a thread safe mutable static HashMap, for example?

Put it in an Arc<Mutex<..>>

But how do you make that a global? Is what I don't understand. It can't be a static can it?

With lazy_static

1 Like

Thanks all, it's really helpful!