From c713ff1e3cd354f65b2a6b6167cb027ddfe2c511 Mon Sep 17 00:00:00 2001 From: ManthanNimodiya Date: Sat, 13 Jun 2026 17:22:34 +0530 Subject: [PATCH 1/9] fix(macos): release leaked window delegate state and reuse a single delegate class instead of registering a new one per window --- .../src-tauri/src/platform/macos/delegates.rs | 105 +++++++++++------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/apps/desktop/src-tauri/src/platform/macos/delegates.rs b/apps/desktop/src-tauri/src/platform/macos/delegates.rs index bdc4583d4f2..e4c08a42cf6 100644 --- a/apps/desktop/src-tauri/src/platform/macos/delegates.rs +++ b/apps/desktop/src-tauri/src/platform/macos/delegates.rs @@ -11,8 +11,7 @@ /// (Hoppscotch) https://github.com/hoppscotch/hoppscotch/blob/286fcd2bb08a84f027b10308d1e18da368f95ebf/packages/hoppscotch-selfhost-desktop/src-tauri/src/mac/window.rs /// (Electron) https://github.com/electron/electron/blob/38512efd25a159ddc64a54c22ef9eb6dd60064ec/shell/browser/native_window_mac.mm#L1454 /// -use objc::{msg_send, sel, sel_impl}; -use rand::{Rng, distributions::Alphanumeric}; +use objc::{class, msg_send, sel, sel_impl}; use tauri::{Emitter, LogicalPosition, Runtime, Window}; pub struct UnsafeWindowHandle(pub *mut std::ffi::c_void); @@ -72,7 +71,8 @@ pub fn setup(window: Window, controls_inset: LogicalPosition use cocoa::appkit::NSWindow; use cocoa::base::{BOOL, id}; use cocoa::foundation::NSUInteger; - use objc::runtime::{Object, Sel}; + use objc::declare::ClassDecl; + use objc::runtime::{Class, Object, Sel}; use std::ffi::c_void; let Ok(ns_win) = window.ns_window() else { @@ -118,10 +118,25 @@ pub fn setup(window: Window, controls_inset: LogicalPosition msg_send![super_del, windowShouldClose: sender] }) } - extern "C" fn on_window_will_close(this: &Object, _cmd: Sel, notification: id) { + extern "C" fn on_window_will_close(this: &Object, _cmd: Sel, notification: id) { suppress_delegate_panic("windowWillClose:", (), || unsafe { let super_del: id = *this.get_ivar("super_delegate"); let _: () = msg_send![super_del, windowWillClose: notification]; + + // Drop the boxed `WindowState` (and the `Window` handle it holds) + // that was leaked via `Box::into_raw` when this delegate was created. + let app_box: *mut c_void = *this.get_ivar("app_box"); + if !app_box.is_null() { + drop(Box::from_raw(app_box as *mut WindowState)); + let this_mut = this as *const Object as *mut Object; + (*this_mut).set_ivar("app_box", std::ptr::null_mut::()); + } + + // NSWindow does not retain its delegate, so the `alloc` reference taken + // when this delegate was created is the only owning reference. Release + // it now that the window is closing. + let this_id = this as *const Object as id; + let _: () = msg_send![this_id, release]; }); } extern "C" fn on_window_did_resize(this: &Object, _cmd: Sel, notification: id) { @@ -329,48 +344,60 @@ pub fn setup(window: Window, controls_inset: LogicalPosition ); } - let window_label = window.label().to_string(); + // Register the delegate class once and reuse it for every window. Previously a brand + // new class was registered (with a randomized name) on every call to `setup`, which + // permanently leaked Objective-C class metadata for the lifetime of the process. + fn get_or_register_delegate_class() -> &'static Class { + static CLASS: std::sync::OnceLock<&'static Class> = std::sync::OnceLock::new(); + *CLASS.get_or_init(|| { + let mut decl = ClassDecl::new("CapWindowDelegate", class!(NSObject)) + .expect("CapWindowDelegate class already registered"); + + decl.add_ivar::("window"); + decl.add_ivar::<*mut c_void>("app_box"); + decl.add_ivar::("toolbar"); + decl.add_ivar::("super_delegate"); + + unsafe { + decl.add_method(sel!(windowShouldClose:), on_window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL); + decl.add_method(sel!(windowWillClose:), on_window_will_close:: as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(windowDidResize:), on_window_did_resize:: as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(windowDidMove:), on_window_did_move as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(windowDidChangeBackingProperties:), on_window_did_change_backing_properties as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(windowDidBecomeKey:), on_window_did_become_key as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(windowDidResignKey:), on_window_did_resign_key as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(draggingEntered:), on_dragging_entered as extern "C" fn(&Object, Sel, id) -> BOOL); + decl.add_method(sel!(prepareForDragOperation:), on_prepare_for_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL); + decl.add_method(sel!(performDragOperation:), on_perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL); + decl.add_method(sel!(concludeDragOperation:), on_conclude_drag_operation as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(draggingExited:), on_dragging_exited as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(window:willUseFullScreenPresentationOptions:), on_window_will_use_full_screen_presentation_options as extern "C" fn(&Object, Sel, id, NSUInteger) -> NSUInteger); + decl.add_method(sel!(windowDidEnterFullScreen:), on_window_did_enter_full_screen:: as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(windowWillEnterFullScreen:), on_window_will_enter_full_screen:: as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(windowDidExitFullScreen:), on_window_did_exit_full_screen:: as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(windowWillExitFullScreen:), on_window_will_exit_full_screen:: as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(windowDidFailToEnterFullScreen:), on_window_did_fail_to_enter_full_screen as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(effectiveAppearanceDidChange:), on_effective_appearance_did_change as extern "C" fn(&Object, Sel, id)); + decl.add_method(sel!(effectiveAppearanceDidChangedOnMainThread:), on_effective_appearance_did_changed_on_main_thread as extern "C" fn(&Object, Sel, id)); + } + + decl.register() + }) + } let app_state = WindowState { window, controls_inset, }; let app_box = Box::into_raw(Box::new(app_state)) as *mut c_void; - let random_str: String = rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(20) - .map(char::from) - .collect(); - // We need to ensure we have a unique delegate name, otherwise we will panic while trying to create a duplicate - // delegate with the same name. - let delegate_name = format!("windowDelegate_cap_{window_label}_{random_str}"); + let delegate_class = get_or_register_delegate_class::(); + let delegate: id = msg_send![delegate_class, alloc]; + (*delegate).set_ivar("window", ns_win_id); + (*delegate).set_ivar("app_box", app_box); + (*delegate).set_ivar("toolbar", cocoa::base::nil); + (*delegate).set_ivar("super_delegate", current_delegate); - ns_win_id.setDelegate_(cocoa::delegate!(&delegate_name, { - window: id = ns_win_id, - app_box: *mut c_void = app_box, - toolbar: id = cocoa::base::nil, - super_delegate: id = current_delegate, - (windowShouldClose:) => on_window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL, - (windowWillClose:) => on_window_will_close as extern "C" fn(&Object, Sel, id), - (windowDidResize:) => on_window_did_resize:: as extern "C" fn(&Object, Sel, id), - (windowDidMove:) => on_window_did_move as extern "C" fn(&Object, Sel, id), - (windowDidChangeBackingProperties:) => on_window_did_change_backing_properties as extern "C" fn(&Object, Sel, id), - (windowDidBecomeKey:) => on_window_did_become_key as extern "C" fn(&Object, Sel, id), - (windowDidResignKey:) => on_window_did_resign_key as extern "C" fn(&Object, Sel, id), - (draggingEntered:) => on_dragging_entered as extern "C" fn(&Object, Sel, id) -> BOOL, - (prepareForDragOperation:) => on_prepare_for_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, - (performDragOperation:) => on_perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, - (concludeDragOperation:) => on_conclude_drag_operation as extern "C" fn(&Object, Sel, id), - (draggingExited:) => on_dragging_exited as extern "C" fn(&Object, Sel, id), - (window:willUseFullScreenPresentationOptions:) => on_window_will_use_full_screen_presentation_options as extern "C" fn(&Object, Sel, id, NSUInteger) -> NSUInteger, - (windowDidEnterFullScreen:) => on_window_did_enter_full_screen:: as extern "C" fn(&Object, Sel, id), - (windowWillEnterFullScreen:) => on_window_will_enter_full_screen:: as extern "C" fn(&Object, Sel, id), - (windowDidExitFullScreen:) => on_window_did_exit_full_screen:: as extern "C" fn(&Object, Sel, id), - (windowWillExitFullScreen:) => on_window_will_exit_full_screen:: as extern "C" fn(&Object, Sel, id), - (windowDidFailToEnterFullScreen:) => on_window_did_fail_to_enter_full_screen as extern "C" fn(&Object, Sel, id), - (effectiveAppearanceDidChange:) => on_effective_appearance_did_change as extern "C" fn(&Object, Sel, id), - (effectiveAppearanceDidChangedOnMainThread:) => on_effective_appearance_did_changed_on_main_thread as extern "C" fn(&Object, Sel, id) - })) + ns_win_id.setDelegate_(delegate) } } From ddd68879406f1fae45cd928b68b064da96bb8c32 Mon Sep 17 00:00:00 2001 From: ManthanNimodiya Date: Sat, 13 Jun 2026 20:54:10 +0530 Subject: [PATCH 2/9] fix(macos): use alloc+new and restore prior delegate before release per review feedback --- .../src-tauri/src/platform/macos/delegates.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/apps/desktop/src-tauri/src/platform/macos/delegates.rs b/apps/desktop/src-tauri/src/platform/macos/delegates.rs index e4c08a42cf6..8c2c765e013 100644 --- a/apps/desktop/src-tauri/src/platform/macos/delegates.rs +++ b/apps/desktop/src-tauri/src/platform/macos/delegates.rs @@ -132,8 +132,13 @@ pub fn setup(window: Window, controls_inset: LogicalPosition (*this_mut).set_ivar("app_box", std::ptr::null_mut::()); } - // NSWindow does not retain its delegate, so the `alloc` reference taken - // when this delegate was created is the only owning reference. Release + // Restore the previous delegate before releasing this one, so any + // further delegate callbacks during teardown don't hit a freed object. + let window: id = *this.get_ivar("window"); + let _: () = msg_send![window, setDelegate: super_del]; + + // NSWindow does not retain its delegate, so the reference taken when + // this delegate was created (`new`) is the only owning one. Release // it now that the window is closing. let this_id = this as *const Object as id; let _: () = msg_send![this_id, release]; @@ -347,6 +352,12 @@ pub fn setup(window: Window, controls_inset: LogicalPosition // Register the delegate class once and reuse it for every window. Previously a brand // new class was registered (with a randomized name) on every call to `setup`, which // permanently leaked Objective-C class metadata for the lifetime of the process. + // + // NOTE: `static CLASS` below is a single process-wide instance shared across every + // monomorphization of this function, not one per `R`. `setup` is only ever called + // with `R = tauri::Wry` in this app, so this is fine in practice; if it were ever + // called with a different `R`, the first call's `on_*::` method pointers would + // be baked into the shared class for all `R`. fn get_or_register_delegate_class() -> &'static Class { static CLASS: std::sync::OnceLock<&'static Class> = std::sync::OnceLock::new(); *CLASS.get_or_init(|| { @@ -392,7 +403,7 @@ pub fn setup(window: Window, controls_inset: LogicalPosition let app_box = Box::into_raw(Box::new(app_state)) as *mut c_void; let delegate_class = get_or_register_delegate_class::(); - let delegate: id = msg_send![delegate_class, alloc]; + let delegate: id = msg_send![delegate_class, new]; (*delegate).set_ivar("window", ns_win_id); (*delegate).set_ivar("app_box", app_box); (*delegate).set_ivar("toolbar", cocoa::base::nil); From f6663a8002f1f70f44f2ce87250facae11e16026 Mon Sep 17 00:00:00 2001 From: ManthanNimodiya Date: Sat, 13 Jun 2026 21:03:13 +0530 Subject: [PATCH 3/9] fix(macos): guard with_window_state against null app_box after windowWillClose --- .../desktop/src-tauri/src/platform/macos/delegates.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/apps/desktop/src-tauri/src/platform/macos/delegates.rs b/apps/desktop/src-tauri/src/platform/macos/delegates.rs index 8c2c765e013..42fb8868fec 100644 --- a/apps/desktop/src-tauri/src/platform/macos/delegates.rs +++ b/apps/desktop/src-tauri/src/platform/macos/delegates.rs @@ -88,10 +88,13 @@ pub fn setup(window: Window, controls_inset: LogicalPosition this: &Object, func: F, ) { - let ptr = unsafe { - let x: *mut c_void = *this.get_ivar("app_box"); - &mut *(x as *mut WindowState) - }; + let x: *mut c_void = unsafe { *this.get_ivar("app_box") }; + // `app_box` is nulled out in `windowWillClose:`; ignore any late + // callbacks that arrive after that instead of dereferencing null. + if x.is_null() { + return; + } + let ptr = unsafe { &mut *(x as *mut WindowState) }; func(ptr); } From 9f4bb63d54872105c53fdd3b351c536cd997f709 Mon Sep 17 00:00:00 2001 From: ManthanNimodiya Date: Sun, 14 Jun 2026 07:17:58 +0530 Subject: [PATCH 4/9] fix(macos): cargo fmt and make windowWillClose cleanup panic-safe regardless of super delegate forward --- .../src-tauri/src/platform/macos/delegates.rs | 109 ++++++++++++++---- 1 file changed, 88 insertions(+), 21 deletions(-) diff --git a/apps/desktop/src-tauri/src/platform/macos/delegates.rs b/apps/desktop/src-tauri/src/platform/macos/delegates.rs index 42fb8868fec..577fd2832c1 100644 --- a/apps/desktop/src-tauri/src/platform/macos/delegates.rs +++ b/apps/desktop/src-tauri/src/platform/macos/delegates.rs @@ -122,10 +122,15 @@ pub fn setup(window: Window, controls_inset: LogicalPosition }) } extern "C" fn on_window_will_close(this: &Object, _cmd: Sel, notification: id) { + let super_del: id = unsafe { *this.get_ivar("super_delegate") }; + + // Forward to the previous delegate first, but don't let a panic there + // skip the cleanup below (which would bring back the leak). suppress_delegate_panic("windowWillClose:", (), || unsafe { - let super_del: id = *this.get_ivar("super_delegate"); let _: () = msg_send![super_del, windowWillClose: notification]; + }); + suppress_delegate_panic("windowWillClose:cleanup", (), || unsafe { // Drop the boxed `WindowState` (and the `Window` handle it holds) // that was leaked via `Box::into_raw` when this delegate was created. let app_box: *mut c_void = *this.get_ivar("app_box"); @@ -373,26 +378,88 @@ pub fn setup(window: Window, controls_inset: LogicalPosition decl.add_ivar::("super_delegate"); unsafe { - decl.add_method(sel!(windowShouldClose:), on_window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL); - decl.add_method(sel!(windowWillClose:), on_window_will_close:: as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(windowDidResize:), on_window_did_resize:: as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(windowDidMove:), on_window_did_move as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(windowDidChangeBackingProperties:), on_window_did_change_backing_properties as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(windowDidBecomeKey:), on_window_did_become_key as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(windowDidResignKey:), on_window_did_resign_key as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(draggingEntered:), on_dragging_entered as extern "C" fn(&Object, Sel, id) -> BOOL); - decl.add_method(sel!(prepareForDragOperation:), on_prepare_for_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL); - decl.add_method(sel!(performDragOperation:), on_perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL); - decl.add_method(sel!(concludeDragOperation:), on_conclude_drag_operation as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(draggingExited:), on_dragging_exited as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(window:willUseFullScreenPresentationOptions:), on_window_will_use_full_screen_presentation_options as extern "C" fn(&Object, Sel, id, NSUInteger) -> NSUInteger); - decl.add_method(sel!(windowDidEnterFullScreen:), on_window_did_enter_full_screen:: as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(windowWillEnterFullScreen:), on_window_will_enter_full_screen:: as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(windowDidExitFullScreen:), on_window_did_exit_full_screen:: as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(windowWillExitFullScreen:), on_window_will_exit_full_screen:: as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(windowDidFailToEnterFullScreen:), on_window_did_fail_to_enter_full_screen as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(effectiveAppearanceDidChange:), on_effective_appearance_did_change as extern "C" fn(&Object, Sel, id)); - decl.add_method(sel!(effectiveAppearanceDidChangedOnMainThread:), on_effective_appearance_did_changed_on_main_thread as extern "C" fn(&Object, Sel, id)); + decl.add_method( + sel!(windowShouldClose:), + on_window_should_close as extern "C" fn(&Object, Sel, id) -> BOOL, + ); + decl.add_method( + sel!(windowWillClose:), + on_window_will_close:: as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowDidResize:), + on_window_did_resize:: as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowDidMove:), + on_window_did_move as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowDidChangeBackingProperties:), + on_window_did_change_backing_properties as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowDidBecomeKey:), + on_window_did_become_key as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowDidResignKey:), + on_window_did_resign_key as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(draggingEntered:), + on_dragging_entered as extern "C" fn(&Object, Sel, id) -> BOOL, + ); + decl.add_method( + sel!(prepareForDragOperation:), + on_prepare_for_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, + ); + decl.add_method( + sel!(performDragOperation:), + on_perform_drag_operation as extern "C" fn(&Object, Sel, id) -> BOOL, + ); + decl.add_method( + sel!(concludeDragOperation:), + on_conclude_drag_operation as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(draggingExited:), + on_dragging_exited as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(window:willUseFullScreenPresentationOptions:), + on_window_will_use_full_screen_presentation_options + as extern "C" fn(&Object, Sel, id, NSUInteger) -> NSUInteger, + ); + decl.add_method( + sel!(windowDidEnterFullScreen:), + on_window_did_enter_full_screen:: as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowWillEnterFullScreen:), + on_window_will_enter_full_screen:: as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowDidExitFullScreen:), + on_window_did_exit_full_screen:: as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowWillExitFullScreen:), + on_window_will_exit_full_screen:: as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(windowDidFailToEnterFullScreen:), + on_window_did_fail_to_enter_full_screen as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(effectiveAppearanceDidChange:), + on_effective_appearance_did_change as extern "C" fn(&Object, Sel, id), + ); + decl.add_method( + sel!(effectiveAppearanceDidChangedOnMainThread:), + on_effective_appearance_did_changed_on_main_thread + as extern "C" fn(&Object, Sel, id), + ); } decl.register() From b50e7fe71c0b06753517a285f044127f4a92cc4d Mon Sep 17 00:00:00 2001 From: ManthanNimodiya Date: Mon, 15 Jun 2026 16:55:01 +0530 Subject: [PATCH 5/9] fix(macos): remove explicit auto-deref flagged by clippy -D warnings --- apps/desktop/src-tauri/src/platform/macos/delegates.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src-tauri/src/platform/macos/delegates.rs b/apps/desktop/src-tauri/src/platform/macos/delegates.rs index 577fd2832c1..79860f418c6 100644 --- a/apps/desktop/src-tauri/src/platform/macos/delegates.rs +++ b/apps/desktop/src-tauri/src/platform/macos/delegates.rs @@ -368,7 +368,7 @@ pub fn setup(window: Window, controls_inset: LogicalPosition // be baked into the shared class for all `R`. fn get_or_register_delegate_class() -> &'static Class { static CLASS: std::sync::OnceLock<&'static Class> = std::sync::OnceLock::new(); - *CLASS.get_or_init(|| { + CLASS.get_or_init(|| { let mut decl = ClassDecl::new("CapWindowDelegate", class!(NSObject)) .expect("CapWindowDelegate class already registered"); From 340569d498d4f310b516ff51532f0eae91a665f8 Mon Sep 17 00:00:00 2001 From: ManthanNimodiya Date: Mon, 15 Jun 2026 16:55:43 +0530 Subject: [PATCH 6/9] fix(recording): cargo fmt memory-leak-detector example to unblock Format CI --- .../examples/memory-leak-detector.rs | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/crates/recording/examples/memory-leak-detector.rs b/crates/recording/examples/memory-leak-detector.rs index 094e3e64e3b..b50ebbcaf2b 100644 --- a/crates/recording/examples/memory-leak-detector.rs +++ b/crates/recording/examples/memory-leak-detector.rs @@ -491,7 +491,10 @@ async fn run_cycles_test( } println!("\n=== Cycle Summary ==="); - println!("{:>6} {:>14} {:>10}", "Cycle", "Footprint(MB)", "Delta prev"); + println!( + "{:>6} {:>14} {:>10}", + "Cycle", "Footprint(MB)", "Delta prev" + ); let mut prev = baseline; for (i, f) in results.iter().enumerate() { let delta = f - prev; @@ -551,8 +554,14 @@ async fn main() -> Result<(), Box> { match mode { "full" => { - run_memory_test(duration, include_camera, include_mic, fragmented, use_oop_muxer) - .await?; + run_memory_test( + duration, + include_camera, + include_mic, + fragmented, + use_oop_muxer, + ) + .await?; } "screen-only" => { run_memory_test(duration, false, false, fragmented, use_oop_muxer).await?; @@ -587,8 +596,14 @@ async fn main() -> Result<(), Box> { .and_then(|s| s.parse().ok()) .unwrap_or(8); - run_cycles_test(cycles, cycle_duration, include_camera, include_mic, fragmented) - .await?; + run_cycles_test( + cycles, + cycle_duration, + include_camera, + include_mic, + fragmented, + ) + .await?; } _ => { println!("Cap Memory Leak Detector"); @@ -607,10 +622,16 @@ async fn main() -> Result<(), Box> { println!(" --no-camera Disable camera"); println!(" --no-mic Disable microphone"); println!(" --no-fragmented Disable fragmented MP4 encoding"); - println!(" --cycles Number of record start/stop cycles (default: 8, cycles mode)"); - println!(" --cycle-duration Recording duration per cycle (default: 8, cycles mode)"); + println!( + " --cycles Number of record start/stop cycles (default: 8, cycles mode)" + ); + println!( + " --cycle-duration Recording duration per cycle (default: 8, cycles mode)" + ); println!(" --oop-muxer Use the out-of-process cap-muxer for fragmented MP4"); - println!(" (requires cap-muxer binary; set CAP_MUXER_BIN or build it)"); + println!( + " (requires cap-muxer binary; set CAP_MUXER_BIN or build it)" + ); println!(); println!("Examples:"); println!(" # Test full pipeline with camera, mic, fragmented MP4 for 2 minutes"); From 49e844e2833c7401fbf8ee7574f405ebcec1430b Mon Sep 17 00:00:00 2001 From: ManthanNimodiya Date: Mon, 15 Jun 2026 17:03:21 +0530 Subject: [PATCH 7/9] fix(macos): reuse existing CapWindowDelegate class instead of panicking if already registered --- apps/desktop/src-tauri/src/platform/macos/delegates.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/desktop/src-tauri/src/platform/macos/delegates.rs b/apps/desktop/src-tauri/src/platform/macos/delegates.rs index 79860f418c6..29456d612df 100644 --- a/apps/desktop/src-tauri/src/platform/macos/delegates.rs +++ b/apps/desktop/src-tauri/src/platform/macos/delegates.rs @@ -369,8 +369,12 @@ pub fn setup(window: Window, controls_inset: LogicalPosition fn get_or_register_delegate_class() -> &'static Class { static CLASS: std::sync::OnceLock<&'static Class> = std::sync::OnceLock::new(); CLASS.get_or_init(|| { + if let Some(existing) = Class::get("CapWindowDelegate") { + return existing; + } + let mut decl = ClassDecl::new("CapWindowDelegate", class!(NSObject)) - .expect("CapWindowDelegate class already registered"); + .expect("failed to register CapWindowDelegate"); decl.add_ivar::("window"); decl.add_ivar::<*mut c_void>("app_box"); From 3f806d77b9691f7f4fe3726bdc7ce2eefa2bb096 Mon Sep 17 00:00:00 2001 From: ManthanNimodiya Date: Mon, 15 Jun 2026 17:23:38 +0530 Subject: [PATCH 8/9] fix(macos): null app_box ivar before dropping WindowState to avoid dangling pointer on re-entrancy --- apps/desktop/src-tauri/src/platform/macos/delegates.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/desktop/src-tauri/src/platform/macos/delegates.rs b/apps/desktop/src-tauri/src/platform/macos/delegates.rs index 29456d612df..d050bde8ae9 100644 --- a/apps/desktop/src-tauri/src/platform/macos/delegates.rs +++ b/apps/desktop/src-tauri/src/platform/macos/delegates.rs @@ -135,9 +135,9 @@ pub fn setup(window: Window, controls_inset: LogicalPosition // that was leaked via `Box::into_raw` when this delegate was created. let app_box: *mut c_void = *this.get_ivar("app_box"); if !app_box.is_null() { - drop(Box::from_raw(app_box as *mut WindowState)); let this_mut = this as *const Object as *mut Object; (*this_mut).set_ivar("app_box", std::ptr::null_mut::()); + drop(Box::from_raw(app_box as *mut WindowState)); } // Restore the previous delegate before releasing this one, so any From 315dfe8495e61c151c40c1d2db722265e692d44c Mon Sep 17 00:00:00 2001 From: ManthanNimodiya Date: Mon, 15 Jun 2026 17:27:29 +0530 Subject: [PATCH 9/9] fix(macos): fall back to existing CapWindowDelegate class if registration races --- apps/desktop/src-tauri/src/platform/macos/delegates.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/desktop/src-tauri/src/platform/macos/delegates.rs b/apps/desktop/src-tauri/src/platform/macos/delegates.rs index d050bde8ae9..65db4237f62 100644 --- a/apps/desktop/src-tauri/src/platform/macos/delegates.rs +++ b/apps/desktop/src-tauri/src/platform/macos/delegates.rs @@ -373,8 +373,13 @@ pub fn setup(window: Window, controls_inset: LogicalPosition return existing; } - let mut decl = ClassDecl::new("CapWindowDelegate", class!(NSObject)) - .expect("failed to register CapWindowDelegate"); + let mut decl = match ClassDecl::new("CapWindowDelegate", class!(NSObject)) { + Some(decl) => decl, + None => { + return Class::get("CapWindowDelegate") + .expect("CapWindowDelegate should exist if already registered"); + } + }; decl.add_ivar::("window"); decl.add_ivar::<*mut c_void>("app_box");