Skip to content

fix: guard qwen_engine std::Mutex poison + null ctx FFI calls#630

Merged
H-Chris233 merged 1 commit into
Open-Less:betafrom
H-Chris233:fix/qwen-engine-mutex-poison-null-ctx-guard
Jun 9, 2026
Merged

fix: guard qwen_engine std::Mutex poison + null ctx FFI calls#630
H-Chris233 merged 1 commit into
Open-Less:betafrom
H-Chris233:fix/qwen-engine-mutex-poison-null-ctx-guard

Conversation

@H-Chris233

@H-Chris233 H-Chris233 commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

User description

修复 dictation 热路径上的潜在崩溃

审计发现 `src/asr/local/qwen_engine.rs` 是整个 codebase 中唯一使用 `std::sync::Mutex`(会 poison)而非 `parking_lot::Mutex` 的锁,位于本地 ASR dictation 热路径上。

修复点

  1. `set_token_handler` — Mutex poison 防护

    • 原代码: `self.token_handler.lock().expect("token_handler poisoned")`
    • 问题: `token_trampoline` 是 C FFI 回调,若 handler 在回调中 panic(即使当前 handler 是安全的,防御不能依赖当前安全),Mutex 会 poison,下次 dictation 调用 `set_token_handler` 时 `.expect()` 直接 panic 杀死进程
    • 修复: 改为 `lock().unwrap_or_else(|poisoned| poisoned.into_inner())` 安全恢复
  2. `transcribe_audio` / `transcribe_stream` — null ctx 防护

    • 在调用 C FFI 前加 `self.ctx.is_null()` 检查,若引擎已被 drop 则返回错误而非 UB
    • defense-in-depth,正常 Arc 生命周期下不会触发

验证

  • `cargo check` 通过
  • `cargo test` 480 passed, 0 failed

PR Type

Bug fix


Description

  • Recover from poisoned Mutex in token handler setter

  • Guard null ctx before C FFI calls in transcribers


Diagram Walkthrough

flowchart LR
    A["set_token_handler lock"] --> B["Recover from poison (unwrap_or_else)"]
    C["transcribe_audio/stream"] --> D["Return error if ctx is null"]
Loading

File Walkthrough

Relevant files
Bug fix
qwen_engine.rs
Guard Mutex poison and null ctx                                                   

openless-all/app/src-tauri/src/asr/local/qwen_engine.rs

  • Replace lock().expect() with unwrap_or_else for poisoned Mutex
    recovery
  • Add is_null() check before FFI calls to avoid undefined behavior
+13/-1   

Two crash-risk fences on the dictation hot path:

1. set_token_handler: Replace std::sync::Mutex::lock().expect() with
   unwrap_or_else(|poisoned| poisoned.into_inner()) to survive a poisoned
   mutex instead of panicking the process. This is the ONLY std Mutex in
   the codebase (all others use parking_lot). If token_trampoline's C FFI
   callback panics, the Mutex poisons and the next dictation crashes.

2. transcribe_audio / transcribe_stream: Add is_null() guard before C FFI
   calls to prevent UB if engine is somehow used after Drop (defense-
   in-depth under normal Arc ownership).
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ No major issues detected

@H-Chris233 H-Chris233 merged commit 9f61c83 into Open-Less:beta Jun 9, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant