What happens
On the 13 x64-asan CI lane, test/regression/issue/30205.test.ts intermittently fails with the inner bun test --isolate subprocess exiting 134 after a fully green run (stderr contains 8 pass, 0 fail, Ran 8 tests across 8 files., then the process aborts). Examples: build 62070 (hard fail), build 62056 and build 61811 (passed on retry).
Cause
The CI test runner sets ASAN_OPTIONS=...detect_leaks=1:abort_on_error=1 and LSAN_OPTIONS=...suppressions=test/leaksan.supp (scripts/runner.node.mjs), and these propagate into subprocesses spawned with bunEnv. At exit of a bun test --isolate run, the last file's test-runner objects are still malloc-live: the Expect wrapper box, its RefData (freed only by Expect::finalize, which requires the wrapper to be GC-finalized), and the file's BunTestCell Rc. LSan reports them as leaks (~600 bytes, 11 allocations in the 30205 fixture), and abort_on_error=1 turns the report into SIGABRT, so a test asserting exitCode === 0 sees 134.
Whether the last file's wrappers get collected before exit is GC-timing dependent, which is why the lane only fails sometimes.
Reproduction (deterministic, unmodified main)
Verified 10/10 failures on main 885c44fea1 with a release-asan build, and the same 10/10 on a current PR branch, i.e. this is not introduced by any in-flight change:
bun scripts/build.ts --profile=release-asan
# fixtures: 8 copies of the f{i}.test.js file from test/regression/issue/30205.test.ts makeFixtures()
cd <fixtures-dir>
BUN_JSC_collectContinuously=1 \
ASAN_OPTIONS="allow_user_segv_handler=1:disable_coredump=0:detect_leaks=1:abort_on_error=1" \
LSAN_OPTIONS="malloc_context_size=30:print_suppressions=0:suppressions=$PWD/test/leaksan.supp" \
./build/release-asan/bun-asan test --isolate .
echo $? # 134
Leak report (main, trimmed to the allocation sites):
Direct leak of 40 byte(s) in 1 object(s) allocated from:
new<bun_runtime::test_runner::expect_core::Expect> boxed.rs
<bun_runtime::test_runner::expect_core::Expect>::call src/runtime/test_runner/expect.rs:656
ExpectClass__call
Indirect leak of 312 byte(s) in 1 object(s) allocated from:
new<alloc::rc::RcInner<bun_runtime::test_runner::bun_test::BunTestCell>>
<bun_runtime::test_runner::bun_test::BunTestRoot>::enter_file src/runtime/test_runner/bun_test.rs:530
Indirect leak of 56 byte(s) in 1 object(s) allocated from:
new<bun_runtime::test_runner::bun_test::RefData> src/ptr/ref_count.rs:844
ref_ src/runtime/test_runner/bun_test.rs:732
<bun_runtime::test_runner::expect_core::Expect>::call src/runtime/test_runner/expect.rs:641
SUMMARY: AddressSanitizer: 600 byte(s) leaked in 11 allocation(s).
Possible fixes
Either make exit finalize the remaining wrappers (a final GC with finalization before exit() in the isolate runner), or add a documented test/leaksan.supp entry for the test-runner exit allocations if the leak is considered acceptable at exit.
What happens
On the
13 x64-asanCI lane,test/regression/issue/30205.test.tsintermittently fails with the innerbun test --isolatesubprocess exiting 134 after a fully green run (stderr contains8 pass,0 fail,Ran 8 tests across 8 files., then the process aborts). Examples: build 62070 (hard fail), build 62056 and build 61811 (passed on retry).Cause
The CI test runner sets
ASAN_OPTIONS=...detect_leaks=1:abort_on_error=1andLSAN_OPTIONS=...suppressions=test/leaksan.supp(scripts/runner.node.mjs), and these propagate into subprocesses spawned withbunEnv. At exit of abun test --isolaterun, the last file's test-runner objects are still malloc-live: theExpectwrapper box, itsRefData(freed only byExpect::finalize, which requires the wrapper to be GC-finalized), and the file'sBunTestCellRc. LSan reports them as leaks (~600 bytes, 11 allocations in the 30205 fixture), andabort_on_error=1turns the report into SIGABRT, so a test assertingexitCode === 0sees 134.Whether the last file's wrappers get collected before exit is GC-timing dependent, which is why the lane only fails sometimes.
Reproduction (deterministic, unmodified main)
Verified 10/10 failures on main
885c44fea1with arelease-asanbuild, and the same 10/10 on a current PR branch, i.e. this is not introduced by any in-flight change:Leak report (main, trimmed to the allocation sites):
Possible fixes
Either make exit finalize the remaining wrappers (a final GC with finalization before
exit()in the isolate runner), or add a documentedtest/leaksan.suppentry for the test-runner exit allocations if the leak is considered acceptable at exit.