-1

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

swapgs
  • 3
  • 2

2 Answers2

2

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.

kmdreko
  • 42,554
  • 6
  • 57
  • 106
  • Thank you so much, this answer is really helpful. So, i guess that the best solution i can come up with is to do as @erikkallen said and replace Rc with Arc? (If the crate will work after that ofc) Or any other ideas? – swapgs Dec 13 '22 at 06:11
0

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.

erikkallen
  • 33,800
  • 13
  • 85
  • 120
  • Yeah, i actually thought about it, but i don't want to mess up the crate, so i am searching for a workaround. I Forgot to mention that crate uses not the std::rc::Rc, but alloc::rc::Rc. I am not sure whether they are the same or not tho. Here is the struct: https://docs.rs/unicorn-engine/latest/src/unicorn_engine/lib.rs.html#154-156 – swapgs Dec 12 '22 at 20:53