Skip to content

Commit b2f83f0

Browse files
fix(core): Replace Rc with Arc to prevent crashes when sending events (#8402)
* fix(core): Prevent crash when sending events. * add change file * use dedicated type for windows refcell map --------- Co-authored-by: Lucas Nogueira <lucas@tauri.app> Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
1 parent 0a2175e commit b2f83f0

File tree

2 files changed

+46
-22
lines changed

2 files changed

+46
-22
lines changed

.changes/prevent-crash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri-runtime-wry": patch:bug
3+
---
4+
5+
Use `Arc` instead of `Rc` to prevent crashes on macOS.

core/tauri-runtime-wry/src/lib.rs

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -268,13 +268,25 @@ pub enum ActiveTracingSpan {
268268
},
269269
}
270270

271+
#[derive(Debug)]
272+
pub struct WindowsStore(RefCell<HashMap<WebviewId, WindowWrapper>>);
273+
274+
// SAFETY: we ensure this type is only used on the main thread.
275+
#[allow(clippy::non_send_fields_in_send_ty)]
276+
unsafe impl Send for WindowsStore {}
277+
278+
// SAFETY: we ensure this type is only used on the main thread.
279+
#[allow(clippy::non_send_fields_in_send_ty)]
280+
unsafe impl Sync for WindowsStore {}
281+
271282
#[derive(Debug, Clone)]
272283
pub struct DispatcherMainThreadContext<T: UserEvent> {
273284
pub window_target: EventLoopWindowTarget<Message<T>>,
274285
pub web_context: WebContextStore,
275286
#[cfg(all(desktop, feature = "global-shortcut"))]
276287
pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
277-
pub windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
288+
// changing this to an Rc will cause frequent app crashes.
289+
pub windows: Arc<WindowsStore>,
278290
#[cfg(all(desktop, feature = "system-tray"))]
279291
system_tray_manager: SystemTrayManager,
280292
#[cfg(feature = "tracing")]
@@ -1973,7 +1985,7 @@ impl<T: UserEvent> Wry<T> {
19731985
#[cfg(all(desktop, feature = "global-shortcut"))]
19741986
let global_shortcut_manager = Rc::new(Mutex::new(WryShortcutManager::new(&event_loop)));
19751987

1976-
let windows = Rc::new(RefCell::new(HashMap::default()));
1988+
let windows = Arc::new(WindowsStore(RefCell::new(HashMap::default())));
19771989
let webview_id_map = WebviewIdStore::default();
19781990

19791991
#[cfg(all(desktop, feature = "system-tray"))]
@@ -2104,6 +2116,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
21042116
.context
21052117
.main_thread
21062118
.windows
2119+
.0
21072120
.borrow_mut()
21082121
.insert(window_id, webview);
21092122

@@ -2337,7 +2350,7 @@ impl<T: UserEvent> Runtime<T> for Wry<T> {
23372350
pub struct EventLoopIterationContext<'a, T: UserEvent> {
23382351
pub callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
23392352
pub webview_id_map: WebviewIdStore,
2340-
pub windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
2353+
pub windows: Arc<WindowsStore>,
23412354
#[cfg(all(desktop, feature = "global-shortcut"))]
23422355
pub global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
23432356
#[cfg(all(desktop, feature = "global-shortcut"))]
@@ -2349,7 +2362,7 @@ pub struct EventLoopIterationContext<'a, T: UserEvent> {
23492362
}
23502363

23512364
struct UserMessageContext {
2352-
windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
2365+
windows: Arc<WindowsStore>,
23532366
webview_id_map: WebviewIdStore,
23542367
#[cfg(all(desktop, feature = "global-shortcut"))]
23552368
global_shortcut_manager: Rc<Mutex<WryShortcutManager>>,
@@ -2384,7 +2397,12 @@ fn handle_user_message<T: UserEvent>(
23842397
},
23852398
Message::Window(id, window_message) => {
23862399
if let WindowMessage::UpdateMenuItem(item_id, update) = window_message {
2387-
if let Some(menu_items) = windows.borrow_mut().get_mut(&id).map(|w| &mut w.menu_items) {
2400+
if let Some(menu_items) = windows
2401+
.0
2402+
.borrow_mut()
2403+
.get_mut(&id)
2404+
.map(|w| &mut w.menu_items)
2405+
{
23882406
if let Some(menu_items) = menu_items.as_mut() {
23892407
let item = menu_items.get_mut(&item_id).expect("menu item not found");
23902408
match update {
@@ -2399,7 +2417,7 @@ fn handle_user_message<T: UserEvent>(
23992417
}
24002418
}
24012419
} else {
2402-
let w = windows.borrow().get(&id).map(|w| {
2420+
let w = windows.0.borrow().get(&id).map(|w| {
24032421
(
24042422
w.inner.clone(),
24052423
w.window_event_listeners.clone(),
@@ -2622,7 +2640,7 @@ fn handle_user_message<T: UserEvent>(
26222640
WebviewMessage::EvaluateScript(script, tx, span) => {
26232641
let _span = span.entered();
26242642
if let Some(WindowHandle::Webview { inner: webview, .. }) =
2625-
windows.borrow().get(&id).and_then(|w| w.inner.as_ref())
2643+
windows.0.borrow().get(&id).and_then(|w| w.inner.as_ref())
26262644
{
26272645
if let Err(e) = webview.evaluate_script(&script) {
26282646
debug_eprintln!("{}", e);
@@ -2633,7 +2651,7 @@ fn handle_user_message<T: UserEvent>(
26332651
#[cfg(not(feature = "tracing"))]
26342652
WebviewMessage::EvaluateScript(script) => {
26352653
if let Some(WindowHandle::Webview { inner: webview, .. }) =
2636-
windows.borrow().get(&id).and_then(|w| w.inner.as_ref())
2654+
windows.0.borrow().get(&id).and_then(|w| w.inner.as_ref())
26372655
{
26382656
if let Err(e) = webview.evaluate_script(&script) {
26392657
debug_eprintln!("{}", e);
@@ -2642,7 +2660,7 @@ fn handle_user_message<T: UserEvent>(
26422660
}
26432661
WebviewMessage::Print => {
26442662
if let Some(WindowHandle::Webview { inner: webview, .. }) =
2645-
windows.borrow().get(&id).and_then(|w| w.inner.as_ref())
2663+
windows.0.borrow().get(&id).and_then(|w| w.inner.as_ref())
26462664
{
26472665
let _ = webview.print();
26482666
}
@@ -2651,7 +2669,7 @@ fn handle_user_message<T: UserEvent>(
26512669
},
26522670
Message::CreateWebview(window_id, handler) => match handler(event_loop, web_context) {
26532671
Ok(webview) => {
2654-
windows.borrow_mut().insert(window_id, webview);
2672+
windows.0.borrow_mut().insert(window_id, webview);
26552673
}
26562674
Err(e) => {
26572675
debug_eprintln!("{}", e);
@@ -2664,7 +2682,7 @@ fn handle_user_message<T: UserEvent>(
26642682

26652683
let w = Arc::new(window);
26662684

2667-
windows.borrow_mut().insert(
2685+
windows.0.borrow_mut().insert(
26682686
window_id,
26692687
WindowWrapper {
26702688
label,
@@ -2773,7 +2791,7 @@ fn handle_user_message<T: UserEvent>(
27732791
}
27742792

27752793
let it = RunIteration {
2776-
window_count: windows.borrow().len(),
2794+
window_count: windows.0.borrow().len(),
27772795
};
27782796
it
27792797
}
@@ -2861,6 +2879,7 @@ fn handle_event_loop<T: UserEvent>(
28612879
*webview_id_map.0.lock().unwrap().values().next().unwrap()
28622880
};
28632881
windows
2882+
.0
28642883
.borrow()
28652884
.get(&window_id)
28662885
.unwrap()
@@ -2946,7 +2965,7 @@ fn handle_event_loop<T: UserEvent>(
29462965
}
29472966
Event::UserEvent(Message::Webview(id, WebviewMessage::WebviewEvent(event))) => {
29482967
if let Some(event) = WindowEventWrapper::from(&event).0 {
2949-
let windows = windows.borrow();
2968+
let windows = windows.0.borrow();
29502969
let window = windows.get(&id);
29512970
if let Some(window) = window {
29522971
callback(RunEvent::WindowEvent {
@@ -2967,7 +2986,7 @@ fn handle_event_loop<T: UserEvent>(
29672986
} => {
29682987
if let Some(window_id) = webview_id_map.get(&window_id) {
29692988
{
2970-
let windows_ref = windows.borrow();
2989+
let windows_ref = windows.0.borrow();
29712990
if let Some(window) = windows_ref.get(&window_id) {
29722991
if let Some(event) = WindowEventWrapper::parse(&window.inner, &event).0 {
29732992
let label = window.label.clone();
@@ -2991,7 +3010,7 @@ fn handle_event_loop<T: UserEvent>(
29913010
match event {
29923011
#[cfg(windows)]
29933012
WryWindowEvent::ThemeChanged(theme) => {
2994-
if let Some(window) = windows.borrow().get(&window_id) {
3013+
if let Some(window) = windows.0.borrow().get(&window_id) {
29953014
if let Some(WindowHandle::Webview { inner, .. }) = &window.inner {
29963015
let theme = match theme {
29973016
WryTheme::Dark => wry::webview::Theme::Dark,
@@ -3006,9 +3025,9 @@ fn handle_event_loop<T: UserEvent>(
30063025
on_close_requested(callback, window_id, windows.clone());
30073026
}
30083027
WryWindowEvent::Destroyed => {
3009-
let removed = windows.borrow_mut().remove(&window_id).is_some();
3028+
let removed = windows.0.borrow_mut().remove(&window_id).is_some();
30103029
if removed {
3011-
let is_empty = windows.borrow().is_empty();
3030+
let is_empty = windows.0.borrow().is_empty();
30123031
if is_empty {
30133032
let (tx, rx) = channel();
30143033
callback(RunEvent::ExitRequested { tx });
@@ -3051,18 +3070,18 @@ fn handle_event_loop<T: UserEvent>(
30513070
}
30523071

30533072
let it = RunIteration {
3054-
window_count: windows.borrow().len(),
3073+
window_count: windows.0.borrow().len(),
30553074
};
30563075
it
30573076
}
30583077

30593078
fn on_close_requested<'a, T: UserEvent>(
30603079
callback: &'a mut (dyn FnMut(RunEvent<T>) + 'static),
30613080
window_id: WebviewId,
3062-
windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>,
3081+
windows: Arc<WindowsStore>,
30633082
) {
30643083
let (tx, rx) = channel();
3065-
let windows_ref = windows.borrow();
3084+
let windows_ref = windows.0.borrow();
30663085
if let Some(w) = windows_ref.get(&window_id) {
30673086
let label = w.label.clone();
30683087
let window_event_listeners = w.window_event_listeners.clone();
@@ -3087,8 +3106,8 @@ fn on_close_requested<'a, T: UserEvent>(
30873106
}
30883107
}
30893108

3090-
fn on_window_close(window_id: WebviewId, windows: Rc<RefCell<HashMap<WebviewId, WindowWrapper>>>) {
3091-
if let Some(window_wrapper) = windows.borrow_mut().get_mut(&window_id) {
3109+
fn on_window_close(window_id: WebviewId, windows: Arc<WindowsStore>) {
3110+
if let Some(window_wrapper) = windows.0.borrow_mut().get_mut(&window_id) {
30923111
window_wrapper.inner = None;
30933112
}
30943113
}

0 commit comments

Comments
 (0)