Repository navigation
Conversation
Collaborator
Author
|
Updated 8:29 PM PT - Oct 20th, 2026
✅ @robobun, your commit e896e1c9aa1ed442cc51b03f6a5500709149ccc0 passed in 🧪 To try this PR locally: bunx bun-pr 46016That installs a local version of the PR into your bun-46016 --bun |
Collaborator
Author
|
Status: draft. The fix is oven-sh/mimalloc#61. This PR pins its head commit for verification and moves to the merged commit when that PR is merged. How this was reproduced:
The PR still carries a temporary measurement (100 emulated runs and an exit code probe in the step). It is removed before the PR leaves draft. |
A crash inside ExitProcess leaves the exit code of a run under Intel SDE at 0, so runTest printed PASS for a run whose output had Bun's crash report. A run that prints the crash banner or the bun.report trace link now counts as a failure.
… tests] Runs the emulated test file 7 times to count the crash reports at process exit with the current mimalloc pin. The next commits bump the pin and remove this loop.
…[skip tests] Pins the fork commit in which the Windows mi_scav_wake_one returns before WakeByAddressSingle once RtlDllShutdownInProgress() is true. The temporary measurement loop in verify-baseline.ts stays for this build.
… code probe [skip tests] On Windows only: runs the emulated test file 100 times with the new mimalloc pin, and prints the exit code of a process that calls ExitProcess(3) from an FLS callback inside its ExitProcess(0), natively and under Intel SDE. The step timeout is raised for this build. All of it is removed before merge.
robobun
force-pushed
the
robobun/450ea084/no-scavenger-wake-at-exit
branch
from
October 21, 2026 02:41
3b05b4c to
e896e1c
Compare
Jarred-Sumner
added a commit
that referenced
this pull request
Oct 21, 2026
…6270) ### What does this PR do? Hardening follow-up to #46021. It fixes regressions from #46021 and #44618 that were never released, includes more of the open pull requests that fix a crash, and fixes a few crashes that had no pull request. #### Regressions fixed (none was released) - `spyOn(Bun, "$")`, and the same for `"sql"`, `"postgres"` and `"SQL"`, threw "does not support accessor properties yet". - Async `fs.read`, `fs.write` and `zlib.brotliCompress` on a view over a `WebAssembly.Memory` could lose data or copy far more than they needed. - `node:vm` with `vm.constants.DONT_CONTEXTIFY`: `this` in host accessors, prototype handling, `util.types.isProxy`, `Bun.deepEquals`, `assert.deepEqual` and `console.log` of a context. - `zlib` `stream.flush()` threw for arguments it used to accept, and streams had a new enumerable property. - `Bun.Transpiler` `exports.replace` with the name `"default"`. - `process.env.X = 3000` could store the number once the function was JIT-compiled. - `node:sqlite` and `bun:sqlite` could lose rows at exit. - Dev server: stylesheets shared between pages after a build error. - Shell `cp` of a file onto itself exited 1. - `error.stack`: the frame of `require()` reads `at anonymous (unknown)` again. - `import * as process from "process"` followed by `process.on(...)` threw at load. The EventEmitter methods that the module exports now act on `process`. - `delete res.statusCode; res.end()` in a `node:http` handler threw. It sends 200, as in Node. (from #46128) - `node:tls`, `node:https` and `node:http2`: connection teardown and write callbacks behave as in 1.4.3 and Node again. #### Crash fixes Bundler, parser and CSS: #42286, #46092, #46097, #46177, #46239, #36334, #43024, #40769. `bun test`, `--hot` and `--watch`: #30776, #38206, #38974. Shell: #43183, #37743, #46168, #46207, #34900. `node:http`, `node:http2`, `Bun.serve`, streams: #43449, #45380, #44457, #42197, #42485, #38082, #38124, #46074, #45999, #46045. `node:vm`, native addons, workers: #46129, #46198, #45615, #33412, #38031. Dev server: #42790, #42850, #39488. Other: #35991, #38030, #38586, #40526, #41830, #46029, #46078, #46114, and the bug of #42215. #### Behavior changes - `crypto.randomFill(view, cb)` reports `ERR_CRYPTO_OPERATION_FAILED` if it could not fill the view. It used to report success. - A function registered twice on `process` runs twice, as in Node. (#41830) - Under `--hot`, a reload after an uncaught exception cancels the timers that the failed run created. The new run's timers fire, and so do timers and `fs.watchFile` watchers that earlier runs kept on `globalThis`. The reload also resets the exit code to 0. (#38206) - The parent of a Worker no longer gets an `'error'` event for a failed `Bun.serve` request in that Worker. The error is printed, as on the main thread. - `hash.write()` after `digest()` drops the chunk, as in Node. (#35991) - `http2` over TLS with `server.emit("connection", socket)`: `session.socket` is a `TLSSocket` and a `'connection'` listener fires, as in Node. (#38124) - A `slice()` with no type of a body `Blob` has `type === ""`, as in Node. (#46114) - `util.types.isProxy(globalThis)` is false, as in Node. - A write on a `node:net` or `node:tls` socket that is still pending when the connection closes calls back with `ECANCELED`, as in Node. - `HTMLRewriter.on()` throws for a selector that is nested too deeply. - `Bun.Image`: `maxPixels` also bounds PNG metadata, `metadata()` of a GIF reports the size that gets decoded, and a path with a NUL byte throws. (#40526) - `bun build --no-bundle` with the `base64` or `dataurl` loader prints an error. (#36334) - Bundled output for a default-exported function or class expression changes to `var file_default = function name() {}`, as in esbuild. `.name` is unchanged. (#46097) - A Proxy in the prototype chain of a `node:vm` global is allowed. jsdom 30 with `runScripts` needs this. - `bun:sqlite` commits a write that `iterate()` left open when the main thread exits. An explicit `BEGIN` is still rolled back. - When a Worker stops while a native addon's async work is still running, the addon's finalizers run after that work is done, as in Node. - Shell: `mv -n` and `cp -n` don't overwrite, and `cp` reads `R`, `v` and `n` anywhere in a flag group. #### Performance - Ordinary `node:vm` contexts run at the same speed. With `DONT_CONTEXTIFY`, stores to globals and reads of inherited names in a hot loop cost 10 to 20 % more than on `main`. - A `process.env` write costs 20 to 35 % less than after #46021. - An async read into a `WebAssembly.Memory` view looks through the live memories: about 1.5 µs more with one memory. #### Not included - Taken in part, so these should stay open for the rest: #36334, #38974, #39488, #40526, #40769, #42485, #45615, #45999, #46029, #46092, #46114, #46168, #46207, #46239. - Needs a WebKit change: #34655 #39204 #40170 #40253 #41587 #41900 #42699 #42897 #42903 #43084 #43813 #44518 #44949 #45770 #45804 #45827. - #44723 (covered by #46097), #41675, #42753, #38762, #41475, #46016. ### How did you verify your code works? - Every item was reproduced first on release builds of `main`, of its parent and of 1.4.3, and compared with Node v26 where Node has the API. - Every fix has a test that fails on `main` and passes on a debug + ASAN build of this branch, except where that isn't practical (huge inputs, code that only runs on Windows or macOS). - The regressions were checked on grids of calls against the build before #46021 and against 1.4.3. - Bun's own test suites and Node's `test-vm-*`, `test-http2-*` and `test-zlib-*` files for the areas touched.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
ExitProcesswhen it runs under Intel SDE:panic(main thread): Segmentation fault at address 0x…. The top frames arentdll←mi_scav_wake_one(WakeByAddressSingle, mimallocsrc/scavenger.c:127) ←mi_arenas_page_free_prim← Rust thread-local destructors. 6 of the last 12 builds ofmainprint it inwindows x64 - verify-baseline.ExitProcessterminates every other thread first. A thread-local destructor then frees a page, and mimalloc wakes its scavenger thread, which no longer exists. ntdll reads the wait block of that thread from its stack. Under SDE that stack is not mapped any more.scripts/verify-baseline.tsprints PASS, and each crashing run takes about 27 s longer.Fix
MIMALLOC_COMMITto the fork change: the Windowsmi_scav_wake_onereturns beforeWakeByAddressSingleonceRtlDllShutdownInProgress()is true.LdrShutdownProcess, after the other threads are terminated and before the first callback runs. All four wakes of the scavenger go through this one function, so each exit path is covered.verify-baseline.tsfails a run that prints Bun's crash report, whatever its exit code is.Background
WaitOnAddress.WaitOnAddresswaiter on the stack of that waiter, in a process-wide table. A wake walks the table.mi_scavenger_stop()beforeExitProcess: a join on every exit, and Bun has 9 exit sites. ConsideredTerminateProcess: fix(windows): use TerminateProcess to prevent NAPI module segfault on exit #27829 did that and was reverted. The guard in the fork also covers anexit()call from a native addon.Downsides
Notes
State of this draft. The first commits carry a temporary measurement: the emulated test file runs 7 times in
verify-baseline.ts, first with the current pin and then with the new one. The measurement is removed before this leaves draft.