Skip to content

bun test --isolate leaks the last file's Expect/RefData at exit, aborting ASAN CI lanes (flaky 30205.test.ts failures) #32176

Description

@robobun

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions