Skip to content

[macos] 退出时 QaHotkeyMonitor drop 在非主线程,Carbon API 触发 SIGTRAP 风险 #169

@appergb

Description

@appergb

现象

macOS 上 OpenLess 通过菜单栏"退出"或 Cmd+Q 关闭时,偶尔会立刻 SIGTRAP crash。symbolicated stack trace 通常类似:

```
Application Specific Information:
Must only be used from the main thread

Thread N Crashed:
... AppKit / Carbon RemoveEventHotKey / DisposeEventHotKeyRef
... openless_lib::qa_hotkey::QaHotkeyMonitor::drop
... tauri RunEvent::Exit
```

跟之前 v1.2.9 修过的 "NSWindow 主线程要求" 是同一类问题,发生在退出时机。

根因

qa_hotkey.rs::QaHotkeyMonitor::drop(隐式或显式)会调 `global-hotkey` 的 `unregister` 路径,在 macOS 上底层是 Carbon `RemoveEventHotKey` —— 这个 API 跟 `RegisterEventHotKey` 一样严格要求主线程调用。

lib.rs:225 的 `RunEvent::Exit` callback:

```rust
RunEvent::Exit => {
coordinator.stop_qa_hotkey_listener(); // → QaHotkeyMonitor drop
}
```

RunEvent::Exit 回调在 macOS 上不保证在 AppKit 主线程跑(tauri-runtime-wry 内部线程模型决定)。如果 drop 落在非主线程,Carbon 触发 `__assert_failed` → SIGTRAP。

对比项目里其他 NSWindow / Carbon 调用都已 wrap 进 `app.run_on_main_thread`,但退出时机这条没加。

影响

  • 仅 macOS
  • 退出时偶发崩(用户视觉上是"OpenLess 退出时弹崩溃报告")
  • 不影响数据 / 用户流程,但有崩溃报告影响信任

建议 fix

`stop_qa_hotkey_listener` 包一层 `run_on_main_thread`:

```rust
pub fn stop_qa_hotkey_listener(&self) {
let inner = Arc::clone(&self.inner);
let app = inner.app.lock().clone();
if let Some(app) = app {
let _ = app.run_on_main_thread(move || {
inner.qa_hotkey.lock().take(); // drop happens on main thread
});
} else {
// app 已 None(极端 shutdown 序),直接 drop(最坏 crash 也是退出时刻)
self.inner.qa_hotkey.lock().take();
}
}
```

注意:`run_on_main_thread` 是 fire-and-forget;退出时机如果主线程 run loop 已经 stop,回调可能不跑。退路:在 `Coordinator::new` 时就把 ns_window 的 `releasedWhenClosed: false` 设上,配合 `AppDelegate.applicationWillTerminate` 提前 unregister。这步比较深,先做最小 fix(`run_on_main_thread`)。

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions