fix(scheduler): remove double-free in limit plugin config update (bug-1685)
User-reported live crash: xce_scheduler SIGABRT via glibc malloc_printerr (heap corruption) inside kill_limit(), called from limit_update_config() during a live config reload. limit_update_config() called kill_limit(limit) in its error path after a failed key_add(privdata->limits, ...). But privdata->limits is a kvmgr created with .datakiller = kill_limit, so on a kvtab-level failure (e.g. -EEXIST for a duplicate limit name -- exactly the rc=-17 captured in the crash's own backtrace), xkvmgr_add() already rolls back via vclear() -> xzarray_clear(), which fires kill_limit(limit) once automatically. The caller's explicit second call was a double free. Removed the redundant call; the kvmgr's own configured datakiller already owns cleanup on this failure path (mirrors the ownership asymmetry job.c's restore_job_array() already documents for the opposite case, where its kvmgr has no datakiller configured and the caller must free failed items itself). One accepted, documented residual gap: a vstore()- level OOM failure (never reaching the kvtab step) would leak `limit` instead -- vanishingly rare, and a leak is strictly better than the guaranteed crash on the common duplicate-name case; xkvmgr_add's return code doesn't distinguish which sub-case occurred, so there's no clean way to free conditionally without a kvmgr API change (out of scope). New test_limit_plugin.c (this plugin had zero test coverage before) -- RED-phase independently reproduced a genuine ASAN heap-use-after-free matching the live crash's exact call chain; GREEN confirms 0 failures. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AgYRU3zDTqNGV5Jk8aiKLg
This commit is contained in:
parent
307f5b82e1
commit
b040dfc068
4 changed files with 307 additions and 7 deletions
|
|
@ -1123,6 +1123,22 @@ sched_scheduler_dispatch_commit_test = executable(
|
|||
dependencies: [scheduler_deps, unity_dep],
|
||||
install: false)
|
||||
|
||||
# White-box regression test for bug-1685 (double-free/heap-corruption
|
||||
# SIGABRT in limit_update_config() on a duplicate limit-name config
|
||||
# update). It #includes ../src/plugins/limit.c directly (same white-box
|
||||
# pattern as sched_picker_registration_test) so it exercises the real
|
||||
# limit_update_config()/limit_init()/limit_priv_data_init() -- all
|
||||
# `static`, otherwise unreachable from a test binary -- not a
|
||||
# re-implementation of any of them. Stubs reset_sched_obj()/get_resvals()/
|
||||
# put_resvals() (scheduler/src, not part of this TU) purely to satisfy the
|
||||
# linker for limit.c code paths this test never exercises -- see the
|
||||
# file's own header comment.
|
||||
sched_limit_plugin_test = executable('sched_limit_plugin_test',
|
||||
['test_limit_plugin.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',
|
||||
|
|
@ -1270,3 +1286,5 @@ test('scheduler decision redelivery test',
|
|||
test('scheduler dispatch commit test',
|
||||
sched_scheduler_dispatch_commit_test, suite: 'scheduler',
|
||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||
test('scheduler limit plugin test', sched_limit_plugin_test, suite: 'scheduler',
|
||||
env: ['ASAN_OPTIONS=detect_leaks=0'])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue