diff --git a/.changes/fix-macos11-stop-task-uaf.md b/.changes/fix-macos11-stop-task-uaf.md new file mode 100644 index 000000000..fb3f457c0 --- /dev/null +++ b/.changes/fix-macos11-stop-task-uaf.md @@ -0,0 +1,5 @@ +--- +"wry": patch +--- + +On macOS 11, fix use-after-free crash in custom protocol `stop_task` during WKWebView dealloc by using raw pointers instead of objc2 references and enforcing correct drop ordering in the async response handler. diff --git a/src/wkwebview/class/url_scheme_handler.rs b/src/wkwebview/class/url_scheme_handler.rs index c280b84c1..58f48b3a6 100644 --- a/src/wkwebview/class/url_scheme_handler.rs +++ b/src/wkwebview/class/url_scheme_handler.rs @@ -286,12 +286,18 @@ extern "C" fn start_task( })) .map_err(|_e| crate::Error::CustomProtocolTaskInvalid)?; - if WEBVIEW_STATE.read().unwrap().contains_key(webview_id) { + let result = if WEBVIEW_STATE.read().unwrap().contains_key(webview_id) { webview.remove_custom_task_key(task_key); Ok(()) } else { Err(crate::Error::CustomProtocolTaskInvalid) - } + }; + + // webview must drop before task: if webview drop triggers dealloc → + // stopAllTasksForPage → platformStopTask, the task must still be alive. + drop(webview); + drop(task); + result } #[cfg(feature = "tracing")] @@ -334,8 +340,8 @@ extern "C" fn start_task( extern "C" fn stop_task( _this: &ProtocolObject, _sel: objc2::runtime::Sel, - webview: &WryWebView, - task: &ProtocolObject, + _webview: *mut AnyObject, + _task: *mut AnyObject, ) { - webview.remove_custom_task_key(task.hash()); + // no-op: avoid accessing task/webview — macOS 11 may pass freed pointers here }