From 64c6dd48eefcfaa791111e528b89863c9bb6db81 Mon Sep 17 00:00:00 2001 From: elia <176603882+7elia@users.noreply.github.com> Date: Sun, 28 Jun 2026 17:41:43 +0200 Subject: [PATCH 1/2] feat(native): use mutexes --- crates/extendify-native/src/vtable_hooks.rs | 106 ++++++++++---------- crates/extendify-native/src/win/mod.rs | 63 ++++++------ 2 files changed, 89 insertions(+), 80 deletions(-) diff --git a/crates/extendify-native/src/vtable_hooks.rs b/crates/extendify-native/src/vtable_hooks.rs index 66985bf..ba00b71 100644 --- a/crates/extendify-native/src/vtable_hooks.rs +++ b/crates/extendify-native/src/vtable_hooks.rs @@ -6,18 +6,21 @@ use crate::cef::{ }; use crate::{callbacks, log}; use std::ffi::c_int; +use std::sync::Mutex; const ENTRYPOINTS: &[&str] = &["/xpui.js", "/xpui-snapshot.js"]; #[allow(unused)] -pub static mut ON_CONTEXT_CREATED_OG: Option< - unsafe extern "C" fn( - *mut _cef_render_process_handler_t, - *mut _cef_browser_t, - *mut _cef_frame_t, - *mut _cef_v8_context_t, - ), -> = None; +pub static ON_CONTEXT_CREATED_OG: Mutex< + Option< + unsafe extern "C" fn( + *mut _cef_render_process_handler_t, + *mut _cef_browser_t, + *mut _cef_frame_t, + *mut _cef_v8_context_t, + ), + >, +> = Mutex::new(None); #[allow(unused)] pub unsafe extern "C" fn on_context_created_hook( self_: *mut _cef_render_process_handler_t, @@ -29,27 +32,27 @@ pub unsafe extern "C" fn on_context_created_hook( callbacks::on_frame(frame); - unsafe { - if let Some(func) = ON_CONTEXT_CREATED_OG { - return func(self_, browser, frame, context); - } + if let Some(func) = ON_CONTEXT_CREATED_OG.lock().ok().and_then(|g| *g) { + unsafe { func(self_, browser, frame, context) }; } - log("Couldn't call original on_context_created"); + log(format!("Couldn't call original {}", stringify!($mutex))); } -pub static mut RES_HANDLER_OG: Option< - unsafe extern "C" fn( - *mut _cef_request_handler_t, - *mut _cef_browser_t, - *mut _cef_frame_t, - *mut _cef_request_t, - c_int, - c_int, - *const cef_string_t, - *mut c_int, - ) -> *mut _cef_resource_request_handler_t, -> = None; +pub static RES_HANDLER_OG: Mutex< + Option< + unsafe extern "C" fn( + *mut _cef_request_handler_t, + *mut _cef_browser_t, + *mut _cef_frame_t, + *mut _cef_request_t, + c_int, + c_int, + *const cef_string_t, + *mut c_int, + ) -> *mut _cef_resource_request_handler_t, + >, +> = Mutex::new(None); pub unsafe extern "C" fn res_handler_hook( self_: *mut _cef_request_handler_t, browser: *mut _cef_browser_t, @@ -60,24 +63,24 @@ pub unsafe extern "C" fn res_handler_hook( initiator: *const cef_string_t, disable_default_handling: *mut c_int, ) -> *mut _cef_resource_request_handler_t { - unsafe { - callbacks::on_frame(frame); + callbacks::on_frame(frame); - let url = ctos((*request).get_url.unwrap()(request)); - if ENTRYPOINTS - .iter() - .any(|entrypoint| url.ends_with(entrypoint)) - { - let header = (*request).get_header_by_name.unwrap()(request, stoc("extendify")); - if header.is_null() { - log("Blocked entrypoint"); + let url = unsafe { ctos((*request).get_url.unwrap()(request)) }; + if ENTRYPOINTS + .iter() + .any(|entrypoint| url.ends_with(entrypoint)) + { + let header = unsafe { (*request).get_header_by_name.unwrap()(request, stoc("extendify")) }; + if header.is_null() { + log("Blocked entrypoint"); - return std::ptr::null_mut(); - } + return std::ptr::null_mut(); } + } - if let Some(func) = RES_HANDLER_OG { - return func( + if let Some(func) = RES_HANDLER_OG.lock().ok().and_then(|g| *g) { + return unsafe { + func( self_, browser, frame, @@ -86,33 +89,32 @@ pub unsafe extern "C" fn res_handler_hook( is_download, initiator, disable_default_handling, - ); - } + ) + }; } - log("Couldn't call original res handler"); std::ptr::null_mut() } #[allow(unused)] -pub static mut GET_REQ_HANDLER_OG: Option< - unsafe extern "C" fn(*mut _cef_client_t) -> *mut _cef_request_handler_t, -> = None; +pub static GET_REQ_HANDLER_OG: Mutex< + Option *mut _cef_request_handler_t>, +> = Mutex::new(None); #[allow(unused)] pub unsafe extern "C" fn get_req_handler_hook( self_: *mut _cef_client_t, ) -> *mut _cef_request_handler_t { - unsafe { - if let Some(func) = GET_REQ_HANDLER_OG { - let handler = func(self_); + if let Some(func) = GET_REQ_HANDLER_OG.lock().ok().and_then(|g| *g) { + let handler = unsafe { func(self_) }; - if !handler.is_null() { - RES_HANDLER_OG = (*handler).get_resource_request_handler; + if !handler.is_null() { + unsafe { + *RES_HANDLER_OG.lock().unwrap() = (*handler).get_resource_request_handler; (*handler).get_resource_request_handler = Some(res_handler_hook); } - - return handler; } + + return handler; } log("Couldn't call original req handler"); diff --git a/crates/extendify-native/src/win/mod.rs b/crates/extendify-native/src/win/mod.rs index 01dc782..942528c 100644 --- a/crates/extendify-native/src/win/mod.rs +++ b/crates/extendify-native/src/win/mod.rs @@ -8,6 +8,7 @@ use slim_detours_sys::{ SlimDetoursAttach, SlimDetoursTransactionBegin, SlimDetoursTransactionCommit, }; use std::ffi::{CString, c_int, c_void}; +use std::sync::Mutex; use windows_sys::Win32::Foundation::HINSTANCE; use windows_sys::Win32::System::LibraryLoader::{GetModuleHandleW, GetProcAddress, LoadLibraryW}; use windows_sys::Win32::System::SystemServices::DLL_PROCESS_ATTACH; @@ -60,10 +61,11 @@ macro_rules! define_hook { let symbol_c = CString::new($symbol).unwrap(); if let Some(target) = GetProcAddress(module, symbol_c.as_ptr() as _) { - $original = Some(std::mem::transmute(target)); + let mut guard = $original.lock().unwrap(); + *guard = Some(std::mem::transmute(target)); SlimDetoursTransactionBegin(); - SlimDetoursAttach(std::ptr::addr_of_mut!($original) as _, $hook as _); + SlimDetoursAttach(guard.as_mut().unwrap() as *mut _ as _, $hook as _); let status = SlimDetoursTransactionCommit(); if status >= 0 { @@ -80,10 +82,11 @@ macro_rules! define_hook { macro_rules! define_inline_hook { ($target: expr, $hook: expr, $original: expr) => { - $original = Some(std::mem::transmute($target)); + let mut guard = $original.lock().unwrap(); + *guard = Some(std::mem::transmute($target)); SlimDetoursTransactionBegin(); - SlimDetoursAttach(std::ptr::addr_of_mut!($original) as _, $hook as _); + SlimDetoursAttach(guard.as_mut().unwrap() as *mut _ as _, $hook as _); let status = SlimDetoursTransactionCommit(); if status >= 0 { @@ -106,14 +109,16 @@ fn init_hooks() { define_hook!("cef_browser_view_create", cef_view_hook, CEF_VIEW_OG); } -static mut CEF_INITIALIZE_OG: Option< - unsafe extern "C" fn( - *const _cef_main_args_t, - *mut _cef_settings_t, - *mut _cef_app_t, - *mut c_void, - ) -> c_int, -> = None; +static CEF_INITIALIZE_OG: Mutex< + Option< + unsafe extern "C" fn( + *const _cef_main_args_t, + *mut _cef_settings_t, + *mut _cef_app_t, + *mut c_void, + ) -> c_int, + >, +> = Mutex::new(None); unsafe extern "C" fn cef_initialize_hook( args: *const _cef_main_args_t, settings: *mut _cef_settings_t, @@ -123,7 +128,7 @@ unsafe extern "C" fn cef_initialize_hook( log(format!("CEF init call on PID {}", std::process::id())); unsafe { - if let Some(func) = CEF_INITIALIZE_OG { + if let Some(func) = CEF_INITIALIZE_OG.lock().ok().and_then(|g| *g) { return func(args, settings, app, std::ptr::null_mut()); } } @@ -132,9 +137,9 @@ unsafe extern "C" fn cef_initialize_hook( 0 } -static mut CEF_PROCESS_OG: Option< - unsafe extern "C" fn(*const _cef_main_args_t, *mut _cef_app_t, *mut c_void) -> c_int, -> = None; +static CEF_PROCESS_OG: Mutex< + Option c_int>, +> = Mutex::new(None); unsafe extern "C" fn cef_process_hook( args: *const _cef_main_args_t, app: *mut _cef_app_t, @@ -156,7 +161,7 @@ unsafe extern "C" fn cef_process_hook( } } - if let Some(func) = CEF_PROCESS_OG { + if let Some(func) = CEF_PROCESS_OG.lock().ok().and_then(|g| *g) { return func(args, app, std::ptr::null_mut()); } } @@ -165,16 +170,18 @@ unsafe extern "C" fn cef_process_hook( 0 } -static mut CEF_VIEW_OG: Option< - unsafe extern "C" fn( - *mut _cef_client_t, - *const cef_string_t, - *const _cef_browser_settings_t, - *mut _cef_dictionary_value_t, - *mut _cef_request_context_t, - *mut _cef_browser_view_delegate_t, - ) -> *mut _cef_browser_view_t, -> = None; +static CEF_VIEW_OG: Mutex< + Option< + unsafe extern "C" fn( + *mut _cef_client_t, + *const cef_string_t, + *const _cef_browser_settings_t, + *mut _cef_dictionary_value_t, + *mut _cef_request_context_t, + *mut _cef_browser_view_delegate_t, + ) -> *mut _cef_browser_view_t, + >, +> = Mutex::new(None); unsafe extern "C" fn cef_view_hook( client: *mut _cef_client_t, url: *const cef_string_t, @@ -193,7 +200,7 @@ unsafe extern "C" fn cef_view_hook( vtable_hooks::RES_HANDLER_OG ); - if let Some(func) = CEF_VIEW_OG { + if let Some(func) = CEF_VIEW_OG.lock().ok().and_then(|g| *g) { return func(client, url, settings, extra_info, request_context, delegate); } } From d10829e8c9d8754c71294b163011e3eab8185efb Mon Sep 17 00:00:00 2001 From: 7elia <176603882+7elia@users.noreply.github.com> Date: Sun, 28 Jun 2026 21:16:04 +0200 Subject: [PATCH 2/2] feat(native): mutexes on unix --- crates/extendify-native/src/unix/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/extendify-native/src/unix/mod.rs b/crates/extendify-native/src/unix/mod.rs index b4d3393..b92e310 100644 --- a/crates/extendify-native/src/unix/mod.rs +++ b/crates/extendify-native/src/unix/mod.rs @@ -4,6 +4,7 @@ use crate::cef::{ _cef_browser_settings_t, _cef_browser_view_delegate_t, _cef_browser_view_t, _cef_client_t, _cef_dictionary_value_t, _cef_request_context_t, cef_string_t, }; +use crate::vtable_hooks::GET_REQ_HANDLER_OG; use crate::{log, vtable_hooks}; #[macro_use] @@ -22,7 +23,7 @@ extern_c_overrides! { let view = real_cef_browser_view_create(client, url, settings, extra_info, request_context, delegate); - vtable_hooks::GET_REQ_HANDLER_OG = (*client).get_request_handler; + *GET_REQ_HANDLER_OG.lock().unwrap() = (*client).get_request_handler; (*client).get_request_handler = Some(vtable_hooks::get_req_handler_hook); view