Skip to content

ai slop - #29322

Closed
robobun wants to merge 2 commits into
mainfrom
farm/147c495c/worker-terminate-uaf
Closed

ai slop#29322
robobun wants to merge 2 commits into
mainfrom
farm/147c495c/worker-terminate-uaf

[autofix.ci] apply automated fixes

c934eb3
Select commit
Loading
Failed to load commit list.
Claude / Claude Code Review completed Apr 15, 2026 in 26m 8s

Code review found 2 important issues

Found 5 candidates, confirmed 2. See review comments for details.

Details

Severity Count
🔴 Important 2
🟡 Nit 0
🟣 Pre-existing 0
Severity File:Line Issue
🔴 Important src/bun.js/web_worker.zig:418-422 WebWorker struct leaks permanently when thread spawn fails (destroy removed from deinit catch path)
🔴 Important src/bun.js/web_worker.zig:657-661 setRef() can re-activate parent_poll_ref after deinit() on natural worker exit

Annotations

Check failure on line 422 in src/bun.js/web_worker.zig

See this annotation in the file changed.

@claude claude / Claude Code Review

WebWorker struct leaks permanently when thread spawn fails (destroy removed from deinit catch path)

The thread-spawn failure path in `WebWorker__updatePtr` now leaks the `WebWorker` struct permanently. Before this PR, `deinit()` ended with `bun.default_allocator.destroy(this)`, so the struct was freed in the catch block when `std.Thread.spawn` failed; after this PR, `destroy` was moved exclusively to `WebWorker__destroy`, which is only reachable via `~Worker()`, but `~Worker()` requires the C++ ref count to reach 0 — and the Zig-held ref (bumped by `worker->ref()` in `Worker::create()`) is onl

Check failure on line 661 in src/bun.js/web_worker.zig

See this annotation in the file changed.

@claude claude / Claude Code Review

setRef() can re-activate parent_poll_ref after deinit() on natural worker exit

After this PR's reordering, `deinit()` runs before `WebWorker__dispatchExit`, so `parent_poll_ref.unrefConcurrently()` fires before the close event reaches the parent thread; if a close event handler then calls `worker.ref()`, `setRef()` passes its only guard (`hasRequestedTerminate()`, which is never set on the natural-exit path) and re-activates `parent_poll_ref`, a ref that is never balanced — `WebWorker__destroy` only frees the struct — causing the parent process to hang indefinitely. Fix: a