From 48893e480f0e38ab8fb92e602a3f0ed4a4cc0fc8 Mon Sep 17 00:00:00 2001 From: Adam Charron Date: Tue, 11 Feb 2025 01:48:59 -0500 Subject: [PATCH] Fix hang in wkwebview implemenation of webview::cookies() --- .changes/wkwebview-race-condition.md | 6 ++++++ src/wkwebview/mod.rs | 14 +++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 .changes/wkwebview-race-condition.md diff --git a/.changes/wkwebview-race-condition.md b/.changes/wkwebview-race-condition.md new file mode 100644 index 000000000..8035f743b --- /dev/null +++ b/.changes/wkwebview-race-condition.md @@ -0,0 +1,6 @@ +--- +wry: minor +--- + +Fix a bug in the wkwebview implementation that could cause hangs and crashes +when wait_for_blocking_operation() was called multiple times in quick succession. \ No newline at end of file diff --git a/src/wkwebview/mod.rs b/src/wkwebview/mod.rs index b80bae84c..2a318b176 100644 --- a/src/wkwebview/mod.rs +++ b/src/wkwebview/mod.rs @@ -78,7 +78,7 @@ use std::{ panic::AssertUnwindSafe, ptr::{null_mut, NonNull}, str::{self, FromStr}, - sync::{Arc, Mutex}, + sync::{Arc, Mutex}, thread, time::Duration, }; #[cfg(feature = "mac-proxy")] @@ -1054,6 +1054,7 @@ unsafe fn window_position(view: &NSView, x: i32, y: i32, height: f64) -> CGPoint CGPoint::new(x as f64, frame.size.height - y as f64 - height) } +/// Wait synchronously for the NSRunLoop to run until a receiver has a message. unsafe fn wait_for_blocking_operation(rx: std::sync::mpsc::Receiver) -> Result { let interval = 0.0002; let limit = 1.; @@ -1061,9 +1062,16 @@ unsafe fn wait_for_blocking_operation(rx: std::sync::mpsc::Receiver) -> Re // run event loop until we get the response back, blocking for at most 3 seconds loop { let rl = objc2_foundation::NSRunLoop::mainRunLoop(); - let d = NSDate::dateWithTimeIntervalSinceNow(interval); - rl.runUntilDate(&d); + let limit_date = NSDate::dateWithTimeIntervalSinceNow(interval); + + let mode = NSString::from_str("NSDefaultRunLoopMode"); + rl.acceptInputForMode_beforeDate(&mode, &limit_date); + thread::sleep(Duration::from_secs_f64(interval)); + if let Ok(response) = rx.try_recv() { + // Extra 1ms just to make sure our runloop is cleared. + // See https://github.com/tauri-apps/wry/pull/1486 for a writeup of why this was added. + thread::sleep(Duration::from_millis(1)); return Ok(response); } elapsed += interval;