Skip to content

Release Bun.serve handler Strongs once the server is idle (native↔JS cycle leak) - #32086

Closed
alii wants to merge 14 commits into
mainfrom
ali/serve-deinit-fixture-retainer
Closed

Release Bun.serve handler Strongs once the server is idle (native↔JS cycle leak)#32086
alii wants to merge 14 commits into
mainfrom
ali/serve-deinit-fixture-retainer

Balance server-side websocket closes; make the drain gate transient

c53235c
Select commit
Loading
Failed to load commit list.
Claude / Claude Code Review completed Jun 12, 2026 in 34m 34s

Code review found 1 important issue

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

Details

Severity Count
🔴 Important 1
🟡 Nit 0
🟣 Pre-existing 0
Severity File:Line Issue
🔴 Important src/runtime/server/ServerWebSocket.rs:1372-1379 ws.close()/terminate() inside a message handler can run the idle unprotect before the enclosing dispatch's run_error_cal

Annotations

Check failure on line 1379 in src/runtime/server/ServerWebSocket.rs

See this annotation in the file changed.

@claude claude / Claude Code Review

ws.close()/terminate() inside a message handler can run the idle unprotect before the enclosing dispatch's run_error_callback reads on_error

Calling `ws.close()`/`ws.terminate()` from inside a `message` (or `drain`/`ping`/`pong`) handler on a gracefully-stopped server's last socket runs `on_websocket_closed()` → `deinit_if_we_can()` → `ws.handler.unprotect()` *before* the enclosing dispatch's tail `run_error_callback` reads `self.on_error`. `unprotect()` doesn't zero the fields, so if the user's handler then allocates (GC collects the now-unrooted `on_error`) and throws, `run_error_callback` calls a freed JSValue. `on_open`'s error p