Skip to content

Navigation Menu

Sign in
Sign up

deps: update hdrhistogram to 0.11.10 - #8

Open
github-actions[bot] wants to merge 1 commit into
main from
deps/update-hdrhistogram
Open

deps: update hdrhistogram to 0.11.10 #8
github-actions[bot] wants to merge 1 commit into
main from
deps/update-hdrhistogram

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 5, 2026

Copy link
Copy Markdown

What does this PR do?

Updates hdrhistogram to version 0.11.10

Compare: HdrHistogram/HdrHistogram_c@be60a99...18c7a32

Auto-updated by this workflow

igorls pushed a commit that referenced this pull request Aug 21, 2026
...rier (oven-sh#36337)
`JSNativeStreamSourceAdapter::m_controller` was a
`JSC::Weak<JSReadableStreamDefaultController>`. When the native pull
promise is rejected (socket fault on a fetch body) the adapter is queued
as the `onNativePullRejected` reaction context, which roots the
**adapter** but not the **controller**: the adapter's only edge to it
was the `Weak`. `FetchTasklet` releases both native `Strong<>`s to the
body stream before that microtask drains, so a GC in between can leave
the entire consumer graph (`controller -> stream -> reader -> pipe op ->
destination -> writer -> readyPromise`) white. The subsequent error
cascade then enqueues the pipe's writes-drained shutdown deferral
against a corpse `op`, and `performPipeShutdownAction(AbortDestination)`
dereferences a swept `readyPromise`:
```
ASSERTION FAILED: result JSObject.h(583) JSGlobalObject *JSC::JSObject::realm() const
#5 JSC::JSObject::realm()
#6 JSC::JSPromise::rejectPromise
#7 JSC::JSPromise::reject
#8 Bun::WebStreams::writableStreamDefaultWriterEnsureReadyPromiseRejected
#9 Bun::WebStreams::writableStreamStartErroring
oven-sh#10 Bun::WebStreams::writableStreamAbort
oven-sh#11 WebCore::performPipeShutdownAction (AbortDestination)
oven-sh#12 WebCore::JSStreamPipeToOperation::onWritesFinishedForShutdown
```
On builds without the assert the same path is a silent write into
freed/reused promise memory.
## Fix
Hold `m_controller` as a visited internal field so a queued adapter
roots the controller directly. The edge is cleared on every terminal
path (`nativeSourcePullRejected`, `nativeSourceCallClose`,
`nativeSourceCancel`); `controller->algorithmContext` is cleared by
`readableStreamDefaultControllerClearAlgorithms`, so the abandoned case
is an ordinary intra-heap cycle mark-sweep collects.
`NewSource::this_jsvalue` is only `Strong` during FileReader I/O, where
pinning the consumer graph is the correct behavior anyway.
With the `Weak` gone the adapter no longer needs a destructor, so it is
now a `JSInternalFieldObjectImpl<5>`: the five JSValue members (handle,
pendingView, closer, drainValue, controller) are internal fields visited
by the base class, with typed accessors at call sites. The scalar
members (chunkSize, flag bitfield, text-decode state) stay as plain
members.
## Verification
`native-source-onclose-leak.test.ts` (the partial-read + `releaseLock`
abandonment tests for Blob/fetch/File sources) continues to pass,
confirming the cycle does not pin. `streams.test.js`,
`pipeTo-signal-leak.test.ts`, `compression.test.ts`, `blob.test.ts` all
pass.
The crash itself is 0/1800 standalone; it reproduces ~1/3 only under a
fault-injected tracer replay. `pipeTo-shutdown-gc.test.ts` exercises the
shape (native body source, socket fault mid-stream, fire-and-forget
`pipeTo` under `collectContinuously`, `AbortDestination` shutdown arm)
as a regression surface.
<!-- robobun:evidence:begin -->
---
**no test proof** · iteration 2 · Platform-specific test(s) that do not
run on this machine. Deferring to CI, which covers all platforms:
test/js/web/streams/pipeTo-shutdown-gc.test.ts
<!-- robobun:evidence:end -->
igorls pushed a commit that referenced this pull request Aug 21, 2026
...llback (oven-sh#36986)
## What
`test/js/node/async_hooks/AsyncLocalStorage-tracking.test.ts` (the
crypto-generateKeyPair fixture) fails on every Linux x64-asan run since
oven-sh#36598 landed (builds
[89023](https://buildkite.com/bun/bun/builds/89023),
[89031](https://buildkite.com/bun/bun/builds/89031)):
```
direct leak of 24b in run (src/runtime/node/node_crypto_binding.rs:85:21) +34 more
SUMMARY: AddressSanitizer: 1480 byte(s) leaked in 35 allocation(s).
 #6 EVP_PKEY_keygen vendor/boringssl/crypto/evp/evp_ctx.cc
 #7 Bun::KeyPairJobCtx::runTask src/jsc/bindings/node/crypto/CryptoGenKeyPair.cpp:23
 #8 Bun__RsaKeyPairJobCtx__runTask src/jsc/bindings/node/crypto/CryptoGenRsaKeyPair.cpp:26
```
## Cause
The 11 extern crypto job ctxs (generateKeyPair x5, sign/verify,
diffieHellman, hkdf, generatePrime, checkPrime, generateKey) completed
by invoking the JS callback from inside C++ `runFromJS` while the ctx
was still alive; the ctx was freed only after `then()` returned. A
callback that never returns (the fixture calls `process.exit(0)` inside
it) stranded everything the ctx still owned: the generated `EVP_PKEY`,
`KeyObjectData` refs, `BIGNUM`s.
The leak is pre-existing; oven-sh#36598 made it observable by routing
`OPENSSL_malloc` through libc under ASAN. Whether LSan reported the
other job types too was codegen luck (their pointers happened to be
reachable by the conservative stack scan); `generateKeyPair`'s
`EVP_PKEY` sits behind two FastMalloc indirections and was reported
deterministically.
## Fix
Make it structurally impossible for a job ctx to hold native resources
across user JS: the native side never sees the callback.
- `runFromJS` keeps its name (the JS-thread half, paired with the
work-pool half `runTask`) but no longer receives the callback. It
returns `JSCallbackArgs`, a small by-value type whose constructors are
the only producers, so bodies read `return { err };` or `return {
jsNull(), publicKey, privateKey };`. The extern "C" shims copy it
through a typed out-pointer (C linkage cannot return a class type); the
Rust side consumes it as a slice.
- The Rust `extern_crypto_job!` plumbing does, in order: run `runFromJS`
to produce the arguments, free the ctx (`ctx_deinit`), invoke the
callback. The invariant lives in one place and applies to every job
type.
- Shutdown release: a completion task enqueued but not yet dispatched
when `process.exit()` runs (exit racing the work pool) used to be
re-queued at shutdown, stranding the ctx the same way. `AnyTaskJob` now
carries an erased release entry and the shutdown release frees the job
without running its completion. A completion posted after the final
drain is not recoverable without joining the work pool (which would
block exit); `test-crypto-op-during-process-exit.js` stays in
`no-validate-leaksan.txt` for that sliver, now with an accurate comment.
- The caught-export-exception paths encoded the `JSC::Exception` cell
itself, so the callback's err argument was not the thrown Error (not
`instanceof Error`, no `code`). They now use `Exception::value()`,
matching node: JWK export of an unsupported curve surfaces
`ERR_CRYPTO_JWK_UNSUPPORTED_CURVE`.
No behavior change otherwise:
- `Bun__EventLoop__runCallback{1,2,3}` were Rust's
`EventLoop::run_callback` exported to C++. The plumbing now calls
`run_callback` directly: same enter/exit bracketing, same
pending-exception gate, same unhandled-exception reporting, same
synchronous timing. This made `runCallback1`/`runCallback3` dead (the
crypto bodies were their last callers), so their exports and
declarations are deleted; `runCallback2` stays for the webview backends.
- Callback arity is preserved per path (observable via
`arguments.length`): error paths pass 1 arg, results 2, generateKeyPair
success 3.
- Exception paths are preserved: a throw out of argument production
skips the callback and reports unhandled, as before. Each `runFromJS`
checks its `ThrowScope` after every call that can throw
(`RETURN_IF_EXCEPTION`), since the check that used to happen inside the
nested `runCallbackN` call now happens after the C++ scope destructs;
`BUN_JSC_validateExceptionChecks` verifies this on the asan lane.
- The produced `JSValue`s live on the `then()` stack frame between
production and invocation, which JSC's conservative scan covers; they
are JS-heap values, so freeing the ctx first cannot invalidate them.
- Perf: same number of FFI crossings, no allocation added.
The Rust-native crypto jobs (pbkdf2, scrypt, random) already had the
ordering property: they resolve promises or queue the callback via
nextTick, so their ctx drops before user JS runs. The
synchronous-callback extern jobs were the gap.
## Verification
New tests in `crypto.key-objects.test.ts`:
- `isASAN`-gated leak suite: children run with
`BUN_DESTRUCT_VM_ON_EXIT=1` and `detect_leaks=1` (the asan lane's
configuration) and call `process.exit(0)` from the callback of each job
type: generateKeyPair (KeyObject and encrypted PEM outputs), sign,
diffieHellman, hkdf, checkPrime, generateKey, plus an
exit-before-completion-dispatch case (busy-spin so the queued completion
is never dispatched).
- An export-error test: `generateKeyPair('ec', { namedCurve:
'secp224r1', ...jwk encodings })` asserts the callback err is
`instanceof Error` with code `ERR_CRYPTO_JWK_UNSUPPORTED_CURVE` (matches
node; fails on main, which passes the Exception cell).
Results:
- unfixed build (src stashed): both generateKeyPair leak tests fail with
the exact CI signature (`Direct leak of 24 byte(s)` in `EVP_PKEY_keygen`
via `KeyPairJobCtx::runTask`)
- fixed build: all pass, including under
`BUN_JSC_validateExceptionChecks=1`, and ec/ed25519 keypair and verify
probes run leak-clean as well
- `AsyncLocalStorage-tracking.test.ts`: 74 pass, 0 fail (all
async-context crypto fixtures, against both bun and node)
- `crypto.test.ts` (369), `crypto.key-objects.test.ts` (117), and 37
node parallel files (`test-crypto-keygen*`, `test-crypto-sign-verify`,
`test-crypto-hkdf`, `test-crypto-dh-stateless`, `test-crypto-*prime*`)
all pass
The break landed with oven-sh#36598 (which made the leak visible); oven-sh#36657
proposed clearing individual ctx fields before the callback, and this PR
supersedes that approach with the ordering guarantee in the job plumbing
instead of per-field resets.
<!-- robobun:evidence:begin -->
---
**no test proof** · iteration 0 · Platform-specific test(s) that do not
run on this machine. Deferring to CI, which covers all platforms:
test/js/node/async_hooks/AsyncLocalStorage-tracking.test.ts
test/js/node/crypto/crypto.key-objects.test.ts
<!-- robobun:evidence:end -->
igorls pushed a commit that referenced this pull request Aug 21, 2026
...wo parallel vecs (oven-sh#39145)
### Problem
- `LOLHTMLContext` in `src/runtime/api/html_rewriter.rs` keeps two vecs,
`selectors` and `element_handlers`, that describe one thing: entry `i`
of each is the selector and the handler object from the same
`rewriter.on(selector, handlers)` call.
- The pairing is only held up by convention: `on_()` pushes to both,
`build_settings()` zips them back together, and a doc comment plus an
invariant comment explain it. The mordant `parallel_vecs` lint flags
this (the one baselined finding for this file).
### Fix
- Add `ElementHandlerEntry { selector, handler: Box<ElementHandler> }`
and store `element_handlers: Vec<ElementHandlerEntry>`. One vec, one
push in `on_()`, and `build_settings()` destructures each entry instead
of zipping.
- No behavior change: the same values are pushed in the same order, the
handler is still boxed (the lol-html closures built in
`build_settings()` hold raw pointers into the box, so it must not move
when the vec reallocates), and the body of the `build_settings()` loop
is unchanged. The `#[expect(clippy::vec_box)]` comes off
`element_handlers` because it is no longer a `Vec<Box<_>>`;
`document_handlers` keeps its own.
- Remove the `parallel_vecs:src/runtime/api/html_rewriter.rs` line from
`mordant-baseline.toml`.
- Tests, in `test/js/workerd/html-rewriter.test.js` (`on()
registrations`), pin down the two things this storage has to get right.
They pass before and after this change, since it is a refactor:
- Many selectors registered on one rewriter, with two rejected `on()`
calls in the middle, each still run the handlers they were registered
with, on two transforms of the same rewriter.
- `on()` called from inside a handler, often enough to reallocate the
registry while lol-html is still calling the handlers registered before
the transform started: the running transform is unaffected and the next
one picks the additions up. With the `Box` removed from
`ElementHandlerEntry` this test fails under ASAN with a
heap-use-after-free (report in the details below), so the boxing is now
covered rather than only commented.
- Verified:
- `bun bd test` on `test/js/workerd/html-rewriter.test.js` (165 tests,
including the new ones), `html-rewriter-end-error.test.ts`,
`html-rewriter-leak.test.ts`,
`test/js/web/html/html-rewriter-doctype.test.ts` and the HTMLRewriter
regression tests: all pass.
 - `cargo clippy -p bun_runtime --no-deps`: clean.
- `cargo dylint --all -p bun_runtime` with this baseline: nothing over
the baseline. The same command with the baseline line removed but the
source change stashed reports exactly the one `parallel_vecs` finding
for this file, so the removed line is the one this change fixes.
- Regenerating the baseline with `MORDANT_BASELINE_WRITE=1` also drops
two entries this PR does not touch
(`always_unwrapped_option:src/install/PackageInstall.rs`,
`narrowed_two_ways:src/runtime/node/node_crypto_binding.rs`); those
findings were already fixed on main by other changes and are left for a
separate cleanup.
### Background
- `HTMLRewriter.on(selector, handlers)` parses the CSS selector with
lol-html and wraps the JS handler object in an `ElementHandler` (the
protected `element`/`comments`/`text` callbacks). Nothing is handed to
lol-html at that point; registrations are collected in `LOLHTMLContext`,
which is shared by the rewriter and every transform it starts, because
`transform()` can run more than once.
- `build_settings()` runs at transform time and turns each registration
into a `(selector, ElementContentHandlers)` pair for lol-html. Its
closures capture a `NonNull<ElementHandler>` pointing into the heap
allocation owned by the `Box`, which is why the handler has to stay
boxed even though clippy would normally suggest otherwise. An `on()`
call after a transform has started (for example from inside a handler)
pushes onto the same vec, which is what makes the reallocation case
reachable from JS.
- `mordant-baseline.toml` is the ratchet for the mordant lint pack run
by the Rust lints workflow: it records the accepted number of findings
per (lint, file), and CI reports anything above those counts. Removing
the line here means a reintroduction of the pattern in this file would
be reported.
<details>
<summary>ASAN report from the new test with the Box removed from
ElementHandlerEntry</summary>
```
ERROR: AddressSanitizer: heap-use-after-free
READ of size 8
 #3 <ElementHandler as HandlerLike>::global src/runtime/api/html_rewriter.rs
 #4 handler_callback::<ElementHandler, Element, ...> src/runtime/api/html_rewriter.rs
 #5 ElementHandler::on_element src/runtime/api/html_rewriter.rs
 #6 build_settings::{closure#0} src/runtime/api/html_rewriter.rs
 #8 lol_html ContentHandlersDispatcher::handle_start_tag
freed by thread T0 here:
 oven-sh#13 RawVec<ElementHandlerEntry>::grow_one
 oven-sh#15 Vec<ElementHandlerEntry>::push
 oven-sh#16 HTMLRewriter::on_ src/runtime/api/html_rewriter.rs
```
</details>
<!-- robobun:evidence:begin -->
---
**no test proof** · iteration 2 · Platform-specific test(s) that do not
run on this machine. Deferring to CI, which covers all platforms:
test/js/workerd/html-rewriter.test.js
<!-- robobun:evidence:end -->
---------
Co-authored-by: Alistair Smith <hi@alistair.sh>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

1 participant

AltStyle によって変換されたページ (->オリジナル) /