myxce/.wolf/bugs/bug-1979.md
lei.chen 00f81c5aa8 fix(testsuite): declare makeResource properly + symmetric teardown in external-skips-inuse test
bug-1979: test.c never included resobj.h, so makeResource() was an
implicitly declared function in this TU -- its 64-bit pointer return was
truncated to int (0x50b000000118 -> 0x118) and sign-extended back.
Dormant since E2 Phase 1 (the test only TEST_ASSERT_NOT_NULL'd it and
re-derived the real pointer via key_find); the leak-fix teardown's
dereference(made) was its first real use and SEGV'd under
ASAN_OPTIONS=detect_leaks=1 (the xce-build.sh all direct-run step).

- include resobj.h: makeResource now declared with its true prototype
- unmeet: memset-only -- sched_check_shared_satisfy_() xvec_idval_init()s
  it itself; the pre-init leaked the vector it replaced (2x4B per call)
- uncomitted: single xvec_init/xvec_fini pair (was init'd twice, fini'd once)
- teardown: collect-then-dereference the refcount-1 resource object, then
  destroy(resmgr), then xstring_table_fini() -- mirrors xce_sched_core_fini()
  (core.c:405)

Verified: ASAN_OPTIONS=detect_leaks=1 direct run rc=0, 17/17 PASS, zero
leak reports; xce-build.sh all green (137/137 suites + manual sched_test
+ Go tests).

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-29 03:22:31 +00:00

92 lines
3.8 KiB
Markdown

---
id: "bug-1979"
status: "open"
status_updated: "2026-10-29"
status_note: "newly logged"
component: "scheduler"
severity: "crash"
timestamp: "2026-10-29T03:16:20Z"
last_seen: "2026-10-29T03:16:20Z"
occurrences: 1
files: ["src/scheduler/testsuite/test.c"]
tags: ["testsuite", "implicit-declaration", "asan", "external-license-resources"]
related: []
summary: "sched_test: makeResource() implicitly declared -- pointer truncated, dereference SEGVs"
---
# bug-1979: makeResource() implicitly declared in sched_test -- pointer truncated, dereference SEGVs
## Description
**Observed:**
`ASAN_OPTIONS=detect_leaks=1 ./scheduler/testsuite/sched_test` SEGVs in
`dereference` after all 17 tests PASS:
```
==659821==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000258
#0 in dereference ../subprojects/librtti/src/ref.c:31
#1 in test_unsatisfy_external_skips_inuse_shared_leg ../scheduler/testsuite/test.c:826
```
**Expected:** the test's teardown `dereference(made)` releases the
refcount-1 resource object registered by `makeResource()`.
**Impact:** sched_test cannot run with leak detection enabled (the
`xce-build.sh all` manual direct-run step); crashes after a clean PASS.
**Found by:** ASAN direct run while closing out the
feature/license-resources -> working merge verification.
## Environment
- OS: Ubuntu 24.04.2 LTS; kernel Linux 6.8.0-147-generic x86_64
- libc: glibc 2.39 (host ldd)
- Toolchain: gcc (GCC) 15.2.0, meson 1.9.1
- Build: asan (xce.build)
- Code: working @ 9b652d93-dirty (test.c local leak-fix edit)
- Deployment: n/a (unit test, no cluster)
## Reproduction
1. `meson compile -C src/xce.build sched_test`
2. `ASAN_OPTIONS=detect_leaks=1 ./src/xce.build/scheduler/testsuite/sched_test`
(full run or `-t test_unsatisfy_external_skips_inuse_shared_leg`)
- Frequency: deterministic
- Evidence: not kept (transient ASAN stderr; repro command above)
## Root cause
`test.c` never includes `resobj.h` and has no local extern, so
`makeResource()` is an *implicitly declared* function in this TU
(gnu17 + this gcc emits only a warning; the build proceeds). An implicit
declaration returns `int`: the real 64-bit pointer `0x50b000000118` is
truncated to 32-bit `eax` (`0x118`) and sign-extended back
(`cltq` visible in the disassembly right after the
`call makeResource`), so `made == 0x118` -- garbage.
The bug was introduced with the test itself (E2 Phase 1, 2fcacac2) but
lay dormant: the test only ever did `TEST_ASSERT_NOT_NULL(made)`
(`0x118 != NULL` always passes) and `key_find`-re-derived the real
pointer into `r` for the flag overwrite. The merge-verification leak fix
added `dereference(made)` in the teardown -- the FIRST real use of the
truncated pointer -- which turned the latent defect into a SEGV.
## Fix
`#include "resobj.h"` in src/scheduler/testsuite/test.c (the header that
declares `extern xce_resource_t* makeResource(var, xce_resource_t*)`),
plus the leak fixes that motivated the teardown:
symmetric single `xvec_init`/`xvec_fini` for `uncomitted`, memset-only
`unmeet` (`sched_check_shared_satisfy_()` xvec_idval_init()s it itself),
and the collect-then-dereference teardown
(`dereference(made)` -> `destroy(core.resmgr)` -> `xstring_table_fini()`,
mirroring `xce_sched_core_fini()`/core.c:405).
## Verification
- Test: test_unsatisfy_external_skips_inuse_shared_leg
(src/scheduler/testsuite/test.c); the SEGV itself was the RED state
(deterministic, both full-run and single-test mode), GREEN after the
include: rc=0, 17/17 PASS, zero leak reports under
`ASAN_OPTIONS=detect_leaks=1`, single-test mode too.
- Suites: `meson test --suite controller` 6/6 OK; full
`xce-build.sh all` re-run pending at logging time.
- Live: n/a (unit test only).
## References
- Related: bug-1429 (the XCE_TESTING reaper convention this teardown
complements), E2 Phase 1 (2fcacac2) where the test was introduced.