Skip to content

test: skip ASAN-gated Node tests on Bun's ASAN builds - #41518

Open
robobun wants to merge 3 commits into
mainfrom
robobun/6bdb099d/node-common-isasan
Open

robobun wants to merge 3 commits into
mainfrom
robobun/6bdb099d/node-common-isasan

Conversation

@robobun

@robobun robobun commented Sep 6, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

  • test/js/node/test/parallel/test-crypto-dh-leak.js fails on the Debian 13 x64-asan lane with AssertionError: before=276508672 after=299560960. The test asserts RSS growth below 20 MB across 50k setPublicKey and setPrivateKey calls. Builds 110810 and 110828 both saw about 22 MB.
  • The growth is the ASAN quarantine, not a leak. Each call frees the old BIGNUM through DH_set0_key, and ASAN keeps freed memory in quarantine instead of reusing it. Locally the same test shows 15 to 18 MB under bun bd, 7 MB with ASAN_OPTIONS=quarantine_size_mb=1, and 4 MB on a release build.
  • Node skips this test under ASAN through common.isASan. Bun's test/js/node/test/common/index.js:311 derives it from process.config.variables.asan === 1, and BunProcess.cpp:2924 always reports 0 (a 1 makes node-gyp build addons with -fsanitize=address). So the skip never fired.

Fix

  • common.isASan is now a lazy getter. It asks the runtime through isASANEnabled from bun:internal-for-testing, the same probe test/harness.ts uses. The node test runner already sets BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING=1, and debug builds expose the module unconditionally. Without the module it falls back to the bun-asan binary name. The getter is lazy because loading bun:internal-for-testing evaluates about a dozen internal modules, and require('../common') must stay cheap for every vendored test.
  • The release, musl, and Windows lanes still run the test, so the leak check is kept where RSS is meaningful.
  • Two other vendored tests read common.isASan: test-crypto-secure-heap.js now skips under ASAN like Node, and test-v8-serialize-leak.js takes its ASAN branch with the same bound.
  • Verified: bun bd test/js/node/test/parallel/test-crypto-dh-leak.js prints 1..0 # Skipped: ASan messes with memory measurements. The release binary still runs the test and passes. test-crypto-secure-heap.js, test-v8-serialize-leak.js, and test-crypto-dh-odd-key.js pass under bun bd.

Background

  • The ASAN allocator puts freed blocks in a quarantine (256 MB by default) so later use-after-free is detected. RSS measured across many free calls therefore grows by about the freed bytes plus redzones, even with no leak.
  • bun:internal-for-testing is a built-in module that is gated behind BUN_FEATURE_FLAG_INTERNAL_FOR_TESTING=1 in release builds. isASANEnabled() is a side-effect-free #if ASAN_ENABLED probe in src/jsc/bindings/InternalForTesting.cpp.
  • No source change is involved. The test file is unchanged since Implement node:crypto DiffieHellman (in native code) #17850 and the DH code has not changed recently. The growth has always sat near the limit on the ASAN lane.

no test proof · iteration 2 · no src or test change; test-proof not applicable

process.config.variables.asan is always 0 in Bun, so common.isASan never
fired and Node tests that skip under ASAN ran on the ASAN lane.
test-crypto-dh-leak.js measures RSS growth, and the ASAN quarantine holds
the freed BIGNUMs, so the growth sits at the 20 MB limit and flakes.
@coderabbitai

coderabbitai Bot commented Sep 6, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Essentials

Run ID: 50154bf6-ecfb-48f3-abe1-b6a65216b9a4

📥 Commits

Reviewing files that changed from the base of the PR and between ee8f984 and a391a91.

📒 Files selected for processing (1)
  • test/js/node/test/common/index.js

Included review availability: Your plan provides up to 10 included reviews per hour; 0 remain after this review.


Walkthrough

ASan detection now supports Node build variables and Bun runtime or executable checks. The result is computed lazily, cached, and exposed through the common.isASan getter.

Changes

ASan Detection

Layer / File(s) Summary
Runtime detection and export
test/js/node/test/common/index.js
ASan detection checks the Node build variable, Bun’s isASANEnabled() API, and the bun-asan executable name. The exported common.isASan property now returns the cached lazy result.

Suggested reviewers: cirospaciari

Merge Risk: ⚪ Minimal · up to 7ae98

This updates vendored Node test ASAN detection to use Bun runtime status lazily and cache the result, enabling ASAN-specific test behavior without an identified merge-blocking risk.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: skipping ASAN-gated Node tests on Bun ASAN builds.
Description check ✅ Passed The description explains the problem, the runtime-based ASAN detection fix, affected tests, lane behavior, and verification results. It does not use the template headings exactly, but it provides the …

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the claude label Sep 6, 2026
@robobun

robobun commented Sep 6, 2026 •

Copy link
Copy Markdown
Collaborator Author
Updated 3:40 AM PT - Sep 6th, 2026

❌ @robobun, your commit 7ae9833 has 1 failures in Build #110952 (All Failures):

  • 📦 Binary size — 8 over 0.50 MB
  • targetthis build canary: main #110907
    sizeΔ
    bun-darwin-aarch6459.44 MB59.25 MB+193.7 KB
    bun-darwin-x6465.75 MB65.29 MB+468.3 KB
    bun-linux-aarch6475.80 MB75.80 MB+1.0 KB
    bun-linux-x6475.92 MB75.89 MB+28.5 KB
    ❌ bun-linux-aarch64-musl69.26 MB68.09 MB+1.16 MB
    ❌ bun-linux-x64-musl70.16 MB68.67 MB+1.49 MB
    ❌ bun-linux-aarch64-android82.84 MB70.18 MB+12.66 MB
    ❌ bun-linux-x64-android85.38 MB72.72 MB+12.65 MB
    ❌ bun-freebsd-x6487.42 MB74.69 MB+12.73 MB
    ❌ bun-freebsd-aarch6490.56 MB77.84 MB+12.73 MB
    ❌ bun-windows-x6482.22 MB81.52 MB+719.5 KB
    ❌ bun-windows-aarch6474.06 MB70.66 MB+3.40 MB

    Add [skip size check] to the commit message if this increase is intentional.


🧪   To try this PR locally:

bunx bun-pr 41518

That installs a local version of the PR into your bun-41518 executable, so you can run:

bun-41518 --bun

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Comment thread test/js/node/test/common/index.js
Loading bun:internal-for-testing evaluates about a dozen internal
modules. Do it only when a test reads common.isASan.
@robobun

robobun commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the one review note in a391a91: the ASAN probe is now lazy, so the vendored tests no longer load bun:internal-for-testing on require('../common'). Only tests that read common.isASan pay for it.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — the follow-up commit made the probe lazy, which addresses the eager bun:internal-for-testing load I flagged earlier.

What was reviewed:

  • getIsASan() is now called only via the get isASan() accessor, so the ~2800 tests that never read it don't pay the internal-module cost.
  • Confirmed isASANEnabled is exported as a function from src/js/internal-for-testing.ts:659, and all three consumers (test-crypto-dh-leak.js, test-crypto-secure-heap.js, test-v8-serialize-leak.js) access it as common.isASan, so the data-property → getter switch is compatible.
  • Fallback chain is sound: process.config.variables.asan → gated runtime probe → bun-asan binary-name check via path.basename; the empty catch is scoped and commented.
Extended reasoning...

Overview

This PR modifies only test/js/node/test/common/index.js, the vendored Node.js test harness. It changes common.isASan from an eager constant (process.config.variables.asan === 1, always false in Bun) to a lazy, memoized getter that probes isASANEnabled() from bun:internal-for-testing and falls back to inspecting the executable name for bun-asan. The goal is to let upstream Node tests that already guard on common.isASan (dh-leak, secure-heap, v8-serialize-leak) actually skip on Bun's ASAN CI lane, where quarantine inflates RSS past the test's fixed threshold.

Security risks

None. This is test-harness-only code with no effect on shipped runtime behavior. No untrusted input is parsed; the try/catch swallows only the expected "module gated" failure and is commented as such. No auth, crypto, or filesystem-write paths are touched.

Level of scrutiny

Low. The change is ~15 lines in a test support file, follows the vendored-test convention of marking Bun-specific deviations with a // Bun: comment, and uses the bun:internal-for-testing mechanism REVIEW.md explicitly endorses for making tests observable without production changes. My earlier review's one concern — that the probe ran at module load and would eagerly pull in the large exposedInternals graph for every one of the ~2800 parallel Node tests — was directly addressed in the second commit by moving evaluation behind a getter with memoization.

Other factors

I verified isASANEnabled exists as export const isASANEnabled: () => boolean in src/js/internal-for-testing.ts, so the typeof === 'function' guard and call are correct. All three in-tree consumers read the value as common.isASan (property access on the exported object), so converting from a data property to an accessor is transparent to them — destructuring would also work since getters fire on destructure. path is already required at the top of common/index.js, so the fallback introduces no new import. The change doesn't weaken any test on non-ASAN lanes: release/musl/Windows still run the leak assertions, which is the point.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review found no issues

No high-confidence issues detected in this change.

@robobun

robobun commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator Author

Status: every test lane passed on build 110952, including the x64-asan lane where test-crypto-dh-leak.js now skips. The only red job is binary-size. It compares against main #110907 (ae7b8f4, #41330 builds JSC from source), and this branch is based on ee8f984, before that change. A test-only diff cannot change the binary size, so a rebase clears it. Ready for review.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant