Note (verified 2026-04-28): The race condition IS real but the line numbers in the original report are wrong. The actual locations are: spawn at kernel/mod.rs:5007, task self-removes at lines 5326/5335, parent inserts at line 5350 — not 5890/6265/6303 as stated.
Severity
P2 — narrow race; gc_sweep eventually cleans up, but stop_agent_run silently no-ops.
Files
crates/librefang-kernel/src/kernel/mod.rs:5007 (spawn)
crates/librefang-kernel/src/kernel/mod.rs:5326, 5335 (task self-removes on completion)
crates/librefang-kernel/src/kernel/mod.rs:5350 (parent inserts abort handle)
Finding
In start_streaming_agent_loop the tokio::spawn at line 5007 begins executing
immediately. The spawned task self-removes its key from running_tasks at lines
5326 / 5335 on completion. The parent inserts (handle.abort_handle()) into
running_tasks at line 5350 after spawn returns.
If the spawned task completes before the parent reaches line 5350 (very fast
turn, e.g., cached error short-circuit, or abort signal racing with spawn),
the task's remove() is a no-op and the parent then inserts a RunningTask
whose abort handle points at an already-finished task.
Side-effects:
- Concurrent caller's
stop_agent_run(agent, session) between insert (5350)
and the gc_sweep cleanup gets an abort handle that targets a dead task — silent no-op.
- The stale entry in
running_tasks blocks a second concurrent turn until gc_sweep removes it.
Fix
Use tokio::task::spawn and store the handle before the async block starts executing, or use a oneshot channel to synchronize the insert with the spawn's first yield point.
Note (verified 2026-04-28): The race condition IS real but the line numbers in the original report are wrong. The actual locations are: spawn at
kernel/mod.rs:5007, task self-removes at lines 5326/5335, parent inserts at line 5350 — not 5890/6265/6303 as stated.Severity
P2 — narrow race; gc_sweep eventually cleans up, but stop_agent_run silently no-ops.
Files
crates/librefang-kernel/src/kernel/mod.rs:5007(spawn)crates/librefang-kernel/src/kernel/mod.rs:5326, 5335(task self-removes on completion)crates/librefang-kernel/src/kernel/mod.rs:5350(parent inserts abort handle)Finding
In
start_streaming_agent_loopthetokio::spawnat line 5007 begins executingimmediately. The spawned task self-removes its key from
running_tasksat lines5326 / 5335 on completion. The parent inserts
(handle.abort_handle())intorunning_tasksat line 5350 after spawn returns.If the spawned task completes before the parent reaches line 5350 (very fast
turn, e.g., cached error short-circuit, or abort signal racing with spawn),
the task's
remove()is a no-op and the parent then inserts aRunningTaskwhose abort handle points at an already-finished task.
Side-effects:
stop_agent_run(agent, session)between insert (5350)and the gc_sweep cleanup gets an abort handle that targets a dead task — silent no-op.
running_tasksblocks a second concurrent turn until gc_sweep removes it.Fix
Use
tokio::task::spawnand store the handle before the async block starts executing, or use aoneshotchannel to synchronize the insert with the spawn's first yield point.