Commit 9509faf
fix(src): close KB watcher start/start TOCTOU race
start_kb_watcher_impl previously performed the lifecycle steps in this
order:
1. KbWatcher::new(&path)
2. watcher.start() (spawns notify threads, starts watching)
3. KB_WATCHER.lock()
4. *guard = Some(watcher)
Between 2 and 3 the watcher is already running on the filesystem but
unreferenced by the global slot. Two concurrent start_kb_watcher
invocations — e.g., a settings "Start" click that double-fires, or a
frontend that retries after a timeout while the first call is still in
flight — could each pass their own check-then-act without observing
each other, and both reach step 4 with their own watcher instance. The
second guard assignment would overwrite the first, but the first
watcher's notify threads keep running on the filesystem as an orphan
with no handle for stop_kb_watcher to reach.
Fix: hold the KB_WATCHER StdMutex guard across the full
check/create/start/store sequence. A racing second starter now observes
the populated slot and returns Ok(false) without ever constructing a
second KbWatcher. KbWatcher::new and watcher.start() are synchronous,
so holding the guard across them does not block other async tasks on
the runtime; the tokio::spawn event-forwarder is moved outside the
critical section so receiving events never contends with KB commands.
Added a SAFETY-style explanatory comment inline; no API or behavior
change for callers other than the correct race resolution.
cargo check --all-targets clean; cargo test --lib passes 311/312 (one
pre-existing #[ignore]'d model-download test).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent aee527a commit 9509faf
1 file changed
Lines changed: 23 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
260 | 260 | | |
261 | 261 | | |
262 | 262 | | |
263 | | - | |
264 | | - | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | | - | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
269 | 277 | | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
270 | 283 | | |
271 | | - | |
| 284 | + | |
| 285 | + | |
272 | 286 | | |
273 | | - | |
| 287 | + | |
| 288 | + | |
274 | 289 | | |
275 | 290 | | |
276 | 291 | | |
| |||
0 commit comments