Skip to content

Commit 88cbb01

Browse files
fix(linux): deadlock in WebViewUriLoader (#1561)
* fix(linux): deadlock in WebViewUriLoader A deadlock could occur, when a WebView was destroyed before handling `LoadEvent::Finished`. Refs tauri-apps/tauri#12589 * unregister listeners --------- Co-authored-by: Lucas Nogueira <[email protected]>
1 parent 3f978d3 commit 88cbb01

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
wry: patch
3+
---
4+
5+
On Linux, fix a deadlock, which could occur when destroying a WebView before loading has finished.

src/webkitgtk/web_context.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
//! Unix platform extensions for [`WebContext`](super::WebContext).
66
77
use crate::{Error, RequestAsyncResponder};
8-
use gtk::glib::{self, MainContext, ObjectExt};
8+
use gtk::{
9+
glib::{self, MainContext, ObjectExt},
10+
traits::WidgetExt,
11+
};
912
use http::{header::CONTENT_TYPE, HeaderName, HeaderValue, Request, Response as HttpResponse};
1013
use soup::{MessageHeaders, MessageHeadersType};
1114
use std::{
@@ -474,13 +477,36 @@ impl WebViewUriLoader {
474477
headers,
475478
}) = self.pop()
476479
{
477-
// we do not need to listen to failed events because those will finish the change event anyways
478-
webview.connect_load_changed(move |_, event| {
480+
// ensure that the lock is released when the webview is destroyed before LoadEvent::Finished is handled
481+
let self_ = self.clone();
482+
let destroy_id = webview.connect_destroy(move |_| {
483+
self_.unlock();
484+
self_.clone().flush();
485+
});
486+
let destroy_id_guard = Mutex::new(Some(destroy_id));
487+
488+
let load_changed_id_guard = Rc::new(Mutex::new(None));
489+
let load_changed_id_guard_ = load_changed_id_guard.clone();
490+
let self_ = self.clone();
491+
// noet: we do not need to listen to failed events because those will finish the change event anyways
492+
let load_changed_id = webview.connect_load_changed(move |w, event| {
479493
if let LoadEvent::Finished = event {
480-
self.unlock();
481-
self.clone().flush();
494+
self_.unlock();
495+
self_.clone().flush();
496+
497+
// unregister listeners
498+
if let Some(id) = destroy_id_guard.lock().unwrap().take() {
499+
w.disconnect(id);
500+
}
501+
if let Some(id) = load_changed_id_guard_.lock().unwrap().take() {
502+
w.disconnect(id);
503+
}
482504
};
483505
});
506+
load_changed_id_guard
507+
.lock()
508+
.unwrap()
509+
.replace(load_changed_id);
484510

485511
if let Some(headers) = headers {
486512
let req = URIRequest::builder().uri(&uri).build();

0 commit comments

Comments
 (0)