fix(scheduler): stop re-dispatching running jobs (bug-1498) + resval double-free (bug-1497)

bug-1498 (re-dispatch): sched_job_is_ready() was a stub returning 1, so any
job lingering in the fcfs pendJobs queue was always elected. A dispatched job
was never marked non-PEND (the controller defers its schedStartJob notify to
the not-yet-implemented apply pump, controller/job.c), so fcfs_update_job
re-enqueued it on every job update and the election thread re-dispatched the
running job — the worker got conflicting signals and the job was SIGTERM'd.

- sched_job_is_ready: elect only PEND, non-suspended jobs
- sched_commit_decision (dispatch): mark the job JOB_STAT_RUN on dispatch so
  it leaves the PEND set and is no longer re-electable
- fcfs_update_job: dedup via ordq_peek before enqueue

bug-1497 (double-free): sched_update's resval paths transferred ownership of
rv->val to sharedInst/w->resvals but left the request pointer set, so
sched_pend_update_killer double-freed it -> use-after-free in
build_host_eval_ctx. Clear rv->val = NULL on transfer.

Tests: new scheduler/testsuite/test_redispatch.c (8 cases): sched_job_is_ready
PEND gating + dispatch-commit marks the job RUN. Full scheduler meson suite
green. Live-verified: a `sleep 60` job is elected exactly once, runs the full
duration and exits 0 (`completed successfully`); before the fix it was
re-dispatched at ~11s and killed (SIGTERM 143).

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
lei.chen 2026-08-04 01:18:45 +00:00
parent 07ab05671d
commit ee7dee0ed4
5 changed files with 381 additions and 2 deletions

View file

@ -56,12 +56,24 @@ sched_job_array_wire_e2e_test = executable('sched_job_array_wire_e2e_test',
dependencies: [scheduler_test_deps],
install: false)
# White-box regression test for bug-1498 (scheduler re-dispatches a job it
# already dispatched): sched_job_is_ready PEND-gating + dispatch-commit marks
# the job RUN. It #includes ../src/scheduler.c directly, so it is a standalone
# TU with its own main() — built as a separate executable.
sched_redispatch_test = executable('sched_redispatch_test',
['test_redispatch.c'],
include_directories:[incdir],
dependencies: [scheduler_test_deps],
install: false)
# Register as meson tests so `meson test --suite scheduler` runs them all.
# detect_leaks=0 matches the suite convention (fixtures are not torn down).
test('scheduler test', scheduler_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'])
test('scheduler job-update test', sched_job_update_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'])
test('scheduler redispatch test', sched_redispatch_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'])
test('scheduler handlers test', sched_handlers_test, suite: 'scheduler',
env: ['ASAN_OPTIONS=detect_leaks=0'])
test('scheduler job-array expand test', sched_job_array_test, suite: 'scheduler',