Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create UnsafeCell<c_void> safely?

Tags:

rust

unsafe

The UnsafeCell documentation says

The UnsafeCell<T> type is the only legal way to obtain aliasable data that is considered mutable.

The only construction method is:

pub const fn new(value: T) -> UnsafeCell<T>

However, it is not possible to create a c_void, we can only create *mut c_void or *const c_void.

Is it possible to create UnsafeCell<c_void> from a *mut c_void? With this, we can let the compiler know that the pointer can point to something mutable.

Or is this not necessary? Can we always use *mut c_void even we know some FFI call will mutate the data it points to and we have multiple references to it?

A use case would be:

struct FFIStruct { v: UnsafeCell<c_void>, other_fields: ... }
impl FFIStruct {
    // We don't want to require &mut self, as we 
    // are sure private call_ffi() will always be called 
    // sequentially, and we don't want to stop
    // status() being callable during the call
    fn call_ffi(&self){ ffi_function(self.v.get()) }
    pub fn status(&self) -> FFIStatus { ... }
}

Now how do we create FFIStruct? Or just use *mut c_void would be OK?

Example code to create &Cell<c_void>

Requires #![feature(as_cell)]:

unsafe fn get_cell<'a>(p: *mut c_void) -> &'a Cell<c_void> {
    Cell::from_mut(&mut *p)
}
like image 454
Earth Engine Avatar asked Sep 01 '25 02:09

Earth Engine


1 Answers

TL;DR: Just use *mut Foo. Cells of any kind are not needed here.


Disclaimer: there is no formal Rust memory model, yet.

You cannot create this type, period, because you cannot1 create an instance of c_void.

The thing is, you don't need to create such a type. Aliasing is not spatial but temporal. You can have multiple *mut T pointing to the same place and it doesn't matter until you try to access one. This essentially converts it to a reference and the aliasing requirements need to be upheld while that reference is around.

raw pointers fall outside of Rust's safe memory model.

The Rustonomicon

Different from references and smart pointers, raw pointers:

  • Are allowed to ignore the borrowing rules by having both immutable and mutable pointers or multiple mutable pointers to the same location
  • Aren’t guaranteed to point to valid memory
  • Are allowed to be null
  • Don’t implement any automatic cleanup

¸— The Rust Programming Language

See also:

  • Why does modifying a mutable reference's value through a raw pointer not violate Rust's aliasing rules?
  • What's the Rust idiom to define a field pointing to a C opaque pointer?
  • Is it undefined behavior to do runtime borrow management with the help of raw pointers in Rust?
  • Can an FFI function modify a variable that wasn't declared mutable?

1 You technically can, but that's only because of an implementation and backwards compatibility limitation.

like image 115
Shepmaster Avatar answered Sep 03 '25 23:09

Shepmaster