]> git.kaiwu.me - haproxy.git/commit
BUG/MEDIUM: task: do not destroy twice the tasks already killed in mworker_cleantasks()
authorWilliam Lallemand <wlallemand@haproxy.com>
Wed, 21 Oct 2026 09:45:32 +0000 (09:45 +0000)
committerWilliam Lallemand <wlallemand@haproxy.com>
Wed, 21 Oct 2026 09:54:18 +0000 (11:54 +0200)
commit8d523c5e83e7193d9e202dd914227d9291a3e230
treeee374af8edfde24a78bbef378a28f785c97c7b2e
parent76602594b514cff28e385e120af6da669663f436
BUG/MEDIUM: task: do not destroy twice the tasks already killed in mworker_cleantasks()

Since 9228fabe34 ("BUG/MEDIUM: task: Do not destroy a task that is not ours
in task_destroy"), task_destroy() calls task_kill() for a task that is not
owned by the current thread. task_kill() is not idempotent: it starts with
BUG_ON(state & TASK_KILLED), so a task which was already flagged as killed
while still being linked in a run or wait queue cannot be destroyed again.

On the 3.0 and 2.8 branches this is reachable by simply starting haproxy in
master-worker mode with a localpeer, a peers section and a program section:
the forked program child calls mworker_cleanlisteners(), which destroys the
peers sync task, then mworker_cleantasks() walks the run queue and destroys
it a second time, aborting the child with SIGILL before it reaches execvp().
The program section no longer exists on this branch, but the underlying
invariant is still violated: a task flagged TASK_KILLED by an earlier
task_kill() is deliberately left in its queue (that is how the scheduler
knows it must free it on dequeue), so mworker_cleantasks() can always stumble
upon one. Make the walk robust instead of relying on the callers never
handing it a doomed task.

Fix this by ignoring the tasks that are already flagged TASK_KILLED when
walking the queues from mworker_cleantasks(). Those tasks don't need to be
destroyed again as they're already doomed: the scheduler frees them as
soon as it dequeues them (see run_tasks_from_lists()). The check is applied
to every queue walked there (the shared run queue, and the per-thread run
and timer queues).

This must be backported to all stable branches.
src/task.c