While live-verifying gitea#46, found and fixed a cascade of 5 previously
undetected bugs that together made every usergroup-scoped limit in
limits.yaml silently non-functional:
- Named usergroups/hostgroups (users.yaml/hosts.yaml) were never
registered into the scheduler's group managers (groupmgr_add() had zero
production callers), so any limit referencing one by name could never
resolve real membership.
- An unconfigured limit scope (e.g. no "projects:") arrived as an
empty-but-present capnp group, not NULL, so build_consumer() built a
real empty group (matching no one) instead of falling back to "all".
- Three separate call sites conflated key_find()'s negative "not found"
return with a real error, short-circuiting before ever reaching the
"instantiate on first use" logic right below them -- the same defect
class already fixed once before in this codebase (bug-1495).
- Two call sites passed &(sched->core.resmgr) where a plain handle was
expected, one level of indirection too many, causing RTTI's key_find()
to reject it as an invalid handle.
All five are live-verified: fresh cluster deploys now correctly match and
instantiate usage tracking for all 7 limits in limits.yaml on every job
submission, reproduced across multiple independent from-scratch redeploys.
A 6th, architecturally distinct issue remains open (bug-1789, logged, not
fixed): sched_fill_limit_requests() computes a job's consumption of a
slots-scoped global limit by reading the wrong request vector, so the
numeric cap itself still never binds. This needs a design decision on
intended cross-scope semantics, not a mechanical fix, so it's left for a
follow-up.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hb6Edtj4KbS8CrgEWYdA2E
makeGroup()'s existing-group update path (hit whenever a config-push
re-applies a group name that already has members, e.g. a retried config
push during controller failover) released xce_g_member_t.u.name via
FREEUP() (plain free()). u.name is allocated by makeString(), an
rtti-managed, refcounted pointer that is not a malloc()-base address --
freeing it directly corrupts the heap. group_killer() in the same file
already releases the identical field correctly via dereference().
Switch both FREEUP(m->u.name) call sites to dereference(m->u.name) to
match. Add a regression test that re-applies config for the same group
name twice, reproducing the exact ASAN bad-free at group.c:234 pre-fix.
This is the root cause of the reproducible xce_scheduler
"free(): invalid pointer" SIGABRT crashes seen during 3-attempt
controller-failover config-push retries (8 confirmed core dumps).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>