Repository navigation
fix(shell): prevent double-free during GC finalization - #26626
Conversation
Fixes #26625 This fixes a segmentation fault that occurred when the GC finalizer tried to free shell interpreter resources that were already partially freed during normal shell completion. The issue happened in this sequence: 1. Shell script completes, `finish()` calls `#derefRootShellAndIOIfNeeded()` which frees root_io and root_shell, then sets `this_jsvalue = .zero` 2. GC runs later and calls `deinitFromFinalizer()`, which called `#derefRootShellAndIOIfNeeded()` again 3. The guard `if (this_jsvalue != .zero)` was unreliable for preventing double-free in all scenarios The fix adds an explicit `cleanup_state` enum to track resource ownership: - `needs_full_cleanup`: Nothing cleaned up yet, finalizer must clean everything - `runtime_cleaned`: finish() already cleaned IO/shell, finalizer skips those This was reported on Windows x64 with high GC pressure (many concurrent shell commands), but the vulnerability existed on all platforms. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
Updated 6:21 PM PT - Jan 31st, 2026
❌ @Jarred-Sumner, your commit 19b5a3f has 1 failures in
🧪 To try this PR locally: bunx bun-pr 26626That installs a local version of the PR into your bun-26626 --bun |
WalkthroughThe changes add a cleanup state tracking mechanism to the shell interpreter to prevent double-free crashes during garbage collection finalization. A new Changes
Possibly related PRs
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
I've tried running the build from this PR on Windows three times: it crashed the first time, worked normally the second time, and crashed again the third time. |
## Summary Fixes oven-sh#26625 This fixes a segmentation fault that occurred on Windows x64 when the GC finalizer tried to free shell interpreter resources that were already partially freed during normal shell completion. - Added explicit `cleanup_state` enum to track resource ownership state - `needs_full_cleanup`: Nothing cleaned up yet, finalizer must clean everything - `runtime_cleaned`: `finish()` already cleaned IO/shell, finalizer skips those - Early return in `#derefRootShellAndIOIfNeeded()` when already cleaned - Explicit state-based cleanup in `deinitFromFinalizer()` The vulnerability existed on all platforms but was most reliably triggered on Windows with high GC pressure (many concurrent shell commands). ## Test plan - [x] Build passes (`bun bd`) - [x] New regression test added (`test/regression/issue/26625.test.ts`) - [x] Existing shell tests pass (same 4 pre-existing failures, no new failures) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
Summary
Fixes #26625
This fixes a segmentation fault that occurred on Windows x64 when the GC finalizer tried to free shell interpreter resources that were already partially freed during normal shell completion.
cleanup_stateenum to track resource ownership stateneeds_full_cleanup: Nothing cleaned up yet, finalizer must clean everythingruntime_cleaned:finish()already cleaned IO/shell, finalizer skips those#derefRootShellAndIOIfNeeded()when already cleaneddeinitFromFinalizer()The vulnerability existed on all platforms but was most reliably triggered on Windows with high GC pressure (many concurrent shell commands).
Test plan
bun bd)test/regression/issue/26625.test.ts)🤖 Generated with Claude Code