Home > database >  Rust. UnsafeCell thread safety
Rust. UnsafeCell thread safety

Time:12-13

I'm using the object from a crate, which was not written by me and i have a struct which i would like to use as a global variable, but i get this error:

error[E0277]: `Rc<UnsafeCell<UnicornInner<'static, ()>>>` cannot be sent between threads safely
  --> src\main.rs:76:37
   |
76 | fn init_emulator(emulator_instance: State<EmulatorGlobal>) {
   |                                     ^^^^^^^^^^^^^^^^^^^^^ `Rc<UnsafeCell<UnicornInner<'static, ()>>>` cannot be sent between threads safely
   |
   = help: within `Unicorn<'static, ()>`, the trait `Send` is not implemented for `Rc<UnsafeCell<UnicornInner<'static, ()>>>`
   = note: required because it appears within the type `Unicorn<'static, ()>`
   = note: required for `std::sync::Mutex<Unicorn<'static, ()>>` to implement `Send`
note: required because it appears within the type `EmulatorGlobal`
  --> src\main.rs:27:8
   |
27 | struct EmulatorGlobal(Mutex<Unicorn<'static, ()>>);
   |        ^^^^^^^^^^^^^^
note: required by a bound in `State`
  --> C:\Users\Aslan\.cargo\registry\src\github.com-1ecc6299db9ec823\tauri-1.2.2\src\state.rs:14:25
   |
14 | pub struct State<'r, T: Send   Sync   'static>(&'r T);
   |                         ^^^^ required by this bound in `State`


My guess is that the problem occurs due to usage of "UnsafeCell". I wounder if there is a proper and easy way to "monkeypatch" this code and keep the whole project safe. Below is the code of the struct:

/// A Unicorn emulator instance.
pub struct Unicorn<'a, D: 'a> {
    inner: Rc<UnsafeCell<UnicornInner<'a, D>>>,
}

Any help appreciated.

I am writing an app with tauri, so i defined the variable as follows:

struct EmulatorGlobal(Mutex<Unicorn<'static, ()>>);

Here is it's usage in the code

#[tauri::command]
fn init_emulator(emulator_instance: State<EmulatorGlobal>) {
    let mut unicorn: Unicorn<()> = Unicorn::new(Arch::X86, Mode::MODE_64).expect("ERROR");
}

The emulator's crate

Upd: The struct uses not the std::rc::Rc, but alloc::rc::Rc (Not sure if they are different, but according to the documentation, they seem similar). (Thanks to @erikkallen for reminding)

The struct definition

CodePudding user response:

The core of your question is how to store a unicorn_engine::Unicorn in a static variable (or used for a type constrained to be Send based on your error) and the answer is you cannot.

As the error leaks, it internally uses an Rc which is not thread-safe. Any attempts to "monkeypatch" it into working would be unsound.

A workaround to make use of a non-thread-safe type in a multi-threaded system would be to create a single thread to hold and operate on that object and use channels to communicate actions and/or results to the rest of the system. Though considering this type in particular, it could be very tedious depending on what you are doing.

CodePudding user response:

I'm not a Rust expert, but I'm pretty sure you need an Arc instead of an Rc if you send it between threads.

  • Related