Skip to content

Bun.Transpiler: fix use-after-free in async transform() error messages#30442

Closed
robobun wants to merge 1 commit into
mainfrom
farm/25f8574b/transpiler-async-error-uaf
Closed

Bun.Transpiler: fix use-after-free in async transform() error messages#30442
robobun wants to merge 1 commit into
mainfrom
farm/25f8574b/transpiler-async-error-uaf

Conversation

@robobun

@robobun robobun commented May 9, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes a use-after-free in Bun.Transpiler.prototype.transform() (the async variant) when the input fails to parse.

TransformTask.run() executes on a worker thread and uses a thread-local MimallocArena for parsing. The lexer allocates error message text (e.g. "Unexpected \x00") from this arena via std.fmt.allocPrint(self.allocator, ...). The arena is destroyed when run() returns, but the log messages that reference that text are read later on the main thread in then()log.toJS()Msg.clone(), which memcpys from the freed arena.

Under ASAN this shows up as use-after-poison; in release builds it reads stale/garbage bytes and can manifest as other signals depending on what reuses the arena pages.

Fix: before run() returns (and before arena.deinit() runs), deep-clone each log message into bun.default_allocator so the text, location, and notes all outlive the arena. Msg.clone() already deep-clones data.text, location.file, location.line_text, and each note's Data via bun.clone.

How did you verify your code works?

Minimal repro that crashes the ASAN build before this change and passes after:

const t = new Bun.Transpiler();
for (let i = 0; i < 200; i++) {
  t.transform("\x00\x01\x02").catch(() => {});
  Bun.gc(true);
}

Added as test/js/bun/transpiler/transpiler-async-error-uaf.test.ts, which also asserts the error message content is preserved correctly. All existing test/js/bun/transpiler/ tests pass.

Found by Fuzzilli (fingerprint 11673762e644e33d).

@github-actions github-actions Bot added the claude label May 9, 2026
@robobun

robobun commented May 9, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 4:52 PM PT - May 9th, 2026

@robobun, your commit 7b0e45f has 1 failures in Build #53085 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 30442

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

bun-30442 --bun

@coderabbitai

coderabbitai Bot commented May 9, 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: Pro

Run ID: 215bb84d-20fa-4be9-b1b0-2432b1c9b917

📥 Commits

Reviewing files that changed from the base of the PR and between fe735f8 and 7b0e45f.

📒 Files selected for processing (2)
  • src/runtime/api/JSTranspiler.zig
  • test/js/bun/transpiler/transpiler-async-error-uaf.test.ts

Walkthrough

This PR fixes a use-after-free vulnerability in async transpiler error message handling. A deferred cleanup block clones transpiler log messages during task teardown. A new regression test verifies error messages remain valid when garbage collection occurs between async transpile operations.

Changes

Async Transpiler Memory Safety

Layer / File(s) Summary
Deferred Message Cleanup
src/runtime/api/JSTranspiler.zig
TransformTask.run adds a defer block that clones each message in this.log.msgs.items using bun.handleOom and bun.default_allocator to prevent freed memory access during teardown.
Regression Test
test/js/bun/transpiler/transpiler-async-error-uaf.test.ts
New test queues 200 async transpile operations with null-byte input, triggers garbage collection between submissions, and asserts each parse error message is "Unexpected \x00" to verify messages are not read from freed arena memory.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: fixing a use-after-free bug in Bun.Transpiler's async transform() method when handling error messages.
Description check ✅ Passed The description fully covers both required template sections with comprehensive technical details about the bug, the fix, and verification methods including a minimal repro and test case.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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

@github-actions

github-actions Bot commented May 9, 2026

Copy link
Copy Markdown
Contributor

Found 1 issue this PR may fix:

  1. Issue #28177 - ASAN use-after-poison in RuntimeTranspilerStore.TranspilerJob on a worker thread, caused by reading mimalloc-arena-allocated memory after arena destruction — exactly the bug pattern this PR fixes.

If this is helpful, copy the block below into the PR description to auto-close this issue on merge.

Fixes #28177

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented May 9, 2026

Copy link
Copy Markdown
Contributor

This PR may be a duplicate of:

  1. Fix use-after-free in Bun.Transpiler async transform() errors #29958 - Same fix: clones async transform() log messages into bun.default_allocator before arena teardown to prevent use-after-free
  2. JSTranspiler: fix use-after-free of log messages in async transform() #30180 - Same fix: deep-copies arena-backed log messages via cloneToWithRecycled() before arena deinit in async transform()
  3. Fix use-after-free in Bun.Transpiler async transform() errors #30263 - Same fix: deep-clones log messages into bun.default_allocator in a defer before arena teardown in async transform()
  4. Fix use-after-free in Bun.Transpiler.transform() error reporting #30309 - Same fix: clones each log message into bun.default_allocator via defer to prevent use-after-free in async transform()

🤖 Generated with Claude Code

@robobun

robobun commented May 9, 2026

Copy link
Copy Markdown
Collaborator Author

Duplicate of #29958.

@robobun robobun closed this May 9, 2026
@robobun robobun deleted the farm/25f8574b/transpiler-async-error-uaf branch May 9, 2026 23:51
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