[v24.x backport] buffer: fix Blob.stream() leaking source buffer - #64664
Closed
gabrielbryk wants to merge 241 commits into
Closed
[v24.x backport] buffer: fix Blob.stream() leaking source buffer#64664gabrielbryk wants to merge 241 commits into
gabrielbryk wants to merge 241 commits into
Conversation
Replace the O(n) case-insensitive algorithm-name scan
with an O(1) SafeMap lookup. The map is pre-built at
module init alongside kSupportedAlgorithms.
Hoist the opts object literal used in normalizeAlgorithm
to module level to avoid allocating identical
{ prefix, context } objects on every call.
Pre-compute ObjectKeys() for simpleAlgorithmDictionaries
entries at module init to avoid allocating a new keys
array on every normalizeAlgorithm call.
Signed-off-by: Filip Skokan <[email protected]>
PR-URL: nodejs#62756
Reviewed-By: Yagiz Nizipli <[email protected]>
Replace object spread in nested WebIDL conversion options with stable-shape ordinary objects. This keeps hot dictionary and sequence conversion paths from allocating null-prototype spread results. Apply the same pattern to Web Crypto converter wrappers that override allowResizable or enable [EnforceRange]. Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#62756 Reviewed-By: Yagiz Nizipli <[email protected]>
Signed-off-by: Matteo Collina <[email protected]> PR-URL: nodejs#62562 Reviewed-By: James M Snell <[email protected]>
Signed-off-by: Nad Alaba <[email protected]> PR-URL: nodejs#63117 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
Signed-off-by: avivkeller <[email protected]> PR-URL: nodejs#63493 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: René <[email protected]>
Rename WebCrypto operation parameters and local variables to match the spec terminology. Use operation, algorithm, and key names consistently between the docs and implementation. Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63518 Reviewed-By: René <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
Drive the regression test from the WebCrypto algorithm registry so all supported algorithms and operations must add explicit coverage regardless of whether they are native-job backed or js-based. Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63520 Reviewed-By: René <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: James M Snell <[email protected]>
Refs: nodejs#62761 Signed-off-by: StefanStojanovic <[email protected]> PR-URL: nodejs#63413 Reviewed-By: Vinícius Lourenço Claro Cardoso <[email protected]>
Signed-off-by: Mohamed Sayed <[email protected]> PR-URL: nodejs#63529 Fixes: nodejs#63514 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63556 Reviewed-By: Jordan Harband <[email protected]> Reviewed-By: Chemi Atlow <[email protected]>
Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63556 Reviewed-By: Jordan Harband <[email protected]> Reviewed-By: Chemi Atlow <[email protected]>
Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63556 Reviewed-By: Jordan Harband <[email protected]> Reviewed-By: Chemi Atlow <[email protected]>
Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63556 Reviewed-By: Jordan Harband <[email protected]> Reviewed-By: Chemi Atlow <[email protected]>
Signed-off-by: Mert Can Altin <[email protected]> PR-URL: nodejs#63385 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Gürgün Dayıoğlu <[email protected]>
Fix build warnings by casting the number literals to the size_t constants they are compared against. Signed-off-by: Maya Lekova <[email protected]> PR-URL: nodejs#63490 Reviewed-By: Joyee Cheung <[email protected]> Reviewed-By: Filip Skokan <[email protected]> Reviewed-By: René <[email protected]>
PR-URL: nodejs#63668 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
PR-URL: nodejs#63669 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
Signed-off-by: Mohamed Sayed <[email protected]> PR-URL: nodejs#63601 Fixes: nodejs#63513 Reviewed-By: LiviaMedeiros <[email protected]> Reviewed-By: Matthew Aitken <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
Signed-off-by: RafaelGSS <[email protected]> PR-URL: nodejs#63293 Reviewed-By: Antoine du Hamel <[email protected]>
This function call can fail with `Z_VERSION_ERROR` if the compiled
library vs loaded library mismatched in version number or in
stream structure size.
In those cases, zlib doesn't initialize the `strm_.msg` field to
null. Therefore, when a `CompressionError` object is created via
`ErrorForMessage()`, it can read a stale or uninitialized `strm_.msg`
pointer that will cause a crash.
Example ASAN report:
```
AddressSanitizer: SEGV on unknown address
#0 __strlen_avx2
string/../sysdeps/x86_64/multiarch/strlen-avx2.S:76
nodejs#1 strlen (/work/node/out/Debug/node+0x1a42ab7)
nodejs#2 v8::(anonymous namespace)::StringLength(char const*)
/work/node/out/../deps/v8/src/api/api.cc:7581:16
nodejs#3 v8::(anonymous namespace)::StringLength(unsigned char const*)
/work/node/out/../deps/v8/src/api/api.cc:7587:10
nodejs#4 v8::String::NewFromOneByte(v8::Isolate*,
unsigned char const*, v8::NewStringType, int)
/work/node/out/../deps/v8/src/api/api.cc:7677:3
nodejs#5 node::OneByteString(v8::Isolate*,
char const*, int, v8::NewStringType)
/work/node/out/../src/util-inl.h:166:10
nodejs#6 node::(anonymous namespace)::CompressionStream<
node::(anonymous namespace)::ZlibContext>
::EmitError(node::(anonymous namespace)
::CompressionError const&)
/work/node/out/../src/node_zlib.cc:565:7
nodejs#7 node::(anonymous namespace)::CompressionStream<
node::(anonymous namespace)::ZlibContext>
::CheckError()
/work/node/out/../src/node_zlib.cc:519:5
nodejs#8 node::(anonymous namespace)::CompressionStream<
node::(anonymous namespace)::ZlibContext>
::AfterThreadPoolWork(int)
/work/node/out/../src/node_zlib.cc:543:10
nodejs#9 node::ThreadPoolWork::ScheduleWork()
::'lambda'(uv_work_s*, int)
::operator()(uv_work_s*, int) const
/work/node/out/../src/threadpoolwork-inl.h:57:15
nodejs#10 node::ThreadPoolWork::ScheduleWork()
::'lambda'(uv_work_s*, int)
::__invoke(uv_work_s*, int)
/work/node/out/../src/threadpoolwork-inl.h:48:7
nodejs#11 uv__work_done /work/libuv-1.51.0/src/threadpool.c:330:5
nodejs#12 uv__async_io.part.0
/work/libuv-1.51.0/src/unix/async.c:208:5
```
Signed-off-by: ndossche <[email protected]>
PR-URL: nodejs#63476
Reviewed-By: Anna Henningsen <[email protected]>
Signed-off-by: arbinger <[email protected]> PR-URL: nodejs#63050 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ethan Arrowood <[email protected]>
PR-URL: nodejs#63670 Reviewed-By: Marco Ippolito <[email protected]> Reviewed-By: Chemi Atlow <[email protected]> Reviewed-By: Darshan Sen <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
PR-URL: nodejs#63545 Refs: nodejs#55794 Reviewed-By: Antoine du Hamel <[email protected]>
Signed-off-by: Tobias Nießen <[email protected]> PR-URL: nodejs#63644 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Filip Skokan <[email protected]>
Update the setRawMode documentation to specify that raw mode disables special processing of input characters only. Output processing, such as newline translation on Unix terminals, is not affected. Fixes: nodejs#63059 Signed-off-by: zeeshan56656 <[email protected]> PR-URL: nodejs#63438 Reviewed-By: Anna Henningsen <[email protected]>
A recursively watched directory can be removed after a parent watcher observes it but before the non-native recursive watcher scans it. Ignore ENOENT from the directory scan so this deletion race does not emit an unhandled watcher error. Signed-off-by: Kamat, Trivikram <[email protected]> Assisted-by: openai:gpt-5.5 PR-URL: nodejs#63686 Refs: https://github.com/nodejs/reliability/blob/main/reports/2026-06-01.md#jstest-failure Reviewed-By: Moshe Atlow <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
Use common.nodeProcessAborted() for the intentional abort path so platform-specific abort signals such as SIGILL are accepted. Signed-off-by: Kamat, Trivikram <[email protected]> Assisted-by: openai:gpt-5.5 PR-URL: nodejs#63687 Refs: https://github.com/nodejs/reliability/blob/main/reports/2026-06-01.md#jstest-failure Reviewed-By: Richard Lau <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
Signed-off-by: Herrtian <[email protected]> PR-URL: nodejs#63542 Fixes: nodejs#62774 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Tobias Nießen <[email protected]>
Signed-off-by: Daijiro Wachi <[email protected]> PR-URL: nodejs#63700 Reviewed-By: Stephen Belanger <[email protected]> Reviewed-By: Tierney Cyren <[email protected]> Reviewed-By: Luigi Pinca <[email protected]> Reviewed-By: Rafael Gonzaga <[email protected]>
Signed-off-by: Antoine du Hamel <[email protected]> PR-URL: nodejs#63707 Reviewed-By: Marco Ippolito <[email protected]> Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: Luigi Pinca <[email protected]>
Consolidate the spec's per-chunk predicate chains (CanCloseOrEnqueue, IsLocked, HasDefaultReader, GetNumReadRequests, GetDesiredSize and the writable-side equivalents) into single passes over the controller and stream state, mirror "close queued or in flight" as a boolean flag maintained at the few close-request transition sites, and materialize the TransformStream [[backpressureChangePromise]] record lazily on first observation so backpressure flips nobody is waiting on allocate nothing. Assisted-by: Claude Code Signed-off-by: Matteo Collina <[email protected]> PR-URL: nodejs#64252 Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Filip Skokan <[email protected]>
Signed-off-by: Guy Bedford <[email protected]> PR-URL: nodejs#63951 Reviewed-By: Ethan Arrowood <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Matteo Collina <[email protected]>
Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63104 Backport-PR-URL: nodejs#64629 Reviewed-By: Antoine du Hamel <[email protected]>
Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63134 Backport-PR-URL: nodejs#64629 Reviewed-By: Antoine du Hamel <[email protected]>
Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63556 Backport-PR-URL: nodejs#64629 Reviewed-By: Antoine du Hamel <[email protected]>
Move KeyObject.prototype.toCryptoKey() onto the base KeyObject class and dispatch from the cached native key type. Both secret and asymmetric conversions now pass a KeyObjectHandle through the Web Crypto import paths. Expose KeyObjectHandle.prototype.getKeyType() so asymmetric importers can validate public/private usages without wrapping the handle back into a KeyObject. Secret importers likewise consume KeyObjectHandle directly. Use the shared asymmetric conversion helper to derive public CryptoKeys for SubtleCrypto.getPublicKey(), avoiding the temporary PrivateKeyObject/createPublicKey round trip while keeping usage validation in the import path. Update getPublicKey and KeyObject.toCryptoKey tests to be driven from the Web Crypto supported-algorithm registry so new algorithms require either coverage or an explicit skip. Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63622 Backport-PR-URL: nodejs#64629 Reviewed-By: Antoine du Hamel <[email protected]>
PR-URL: nodejs#63900 Backport-PR-URL: nodejs#64629 Reviewed-By: Antoine du Hamel <[email protected]>
Introduce prepareSubtleMethod() and convertSubtleArgument() for the common SubtleCrypto call prelude. Methods now reuse the same receiver check, required-argument check, error prefix construction, argument context selection, and WebIDL conversion path. Introduce WebCrypto key usage helpers for common usage validation and key pair usage splitting. Algorithm modules now define their allowed public, private, and key generation usages once, then call the shared helpers from generateKey() and importKey() paths. This removes repeated function-invocation setup in webcrypto.js and repeated key usage checks across the WebCrypto algorithm modules while preserving the existing validation behavior. Mark normalized-algorithm fallback branches as unreachable assertions. Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63975 Backport-PR-URL: nodejs#64629 Reviewed-By: Antoine du Hamel <[email protected]>
Add shared bit-length helpers for WebCrypto operations that accept bit sequences whose length is not byte-aligned. Use the helpers for cSHAKE output, ECDH-derived bits, HMAC/KMAC key generation/import/derivation, and KMAC sign/verify output. Preserve the requested bit length in CryptoKey algorithm metadata while storing and exporting rounded-up byte material with unused low bits cleared. Keep byte-multiple validation for algorithms whose specs require it. Extend the lower-end of KMAC's key length support. Enable cSHAKE customization and functionName parameters. Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#63988 Backport-PR-URL: nodejs#64629 Reviewed-By: Antoine du Hamel <[email protected]>
Return false for Ed25519 and Ed448 one-shot verification when the public key or signature R component is a known low-order point. This keeps key import behavior unchanged while making WebCrypto verification match WPT expectations across OpenSSL variants. Remove the stale WPT expected-failure entry and add focused regression coverage for both curves. Closes: nodejs#54572 Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#64026 Backport-PR-URL: nodejs#64629 Fixes: nodejs#54572 Reviewed-By: Antoine du Hamel <[email protected]>
Signed-off-by: Filip Skokan <[email protected]> PR-URL: nodejs#64033 Backport-PR-URL: nodejs#64629 Reviewed-By: Antoine du Hamel <[email protected]>
Original commit message:
optimize ascii fast path in WriteUtf8V2
Change-Id: If28168cb4395b953d0ec642ef4fc618ce963dbcd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7124103
Reviewed-by: Toon Verwaest <[email protected]>
Commit-Queue: Erik Corry <[email protected]>
Reviewed-by: Erik Corry <[email protected]>
Cr-Commit-Position: refs/heads/main@{#103542}
Refs: v8/v8@64b36b4
PR-URL: nodejs#61712
Backport-PR-URL: nodejs#64630
Reviewed-By: Michaël Zasso <[email protected]>
Add a samplePerIteration option to monitorEventLoopDelay that records event loop delay from libuv event loop iterations instead of the timer interval sampler. The default remains interval-based; existing uses of monitorEventLoopDelay() keep behaving the same unless the samplePerIteration option is passed through. Signed-off-by: Pablo Erhard <[email protected]> PR-URL: nodejs#62935 Backport-PR-URL: nodejs#64480 Reviewed-By: Antoine du Hamel <[email protected]>
Signed-off-by: Chengzhong Wu <[email protected]> PR-URL: nodejs#63626 Backport-PR-URL: nodejs#64632 Reviewed-By: Antoine du Hamel <[email protected]>
With the introduction of always static target `node_base`, `node_aix_shared` is now redundant. Signed-off-by: Chengzhong Wu <[email protected]> PR-URL: nodejs#63747 Backport-PR-URL: nodejs#64632 Refs: nodejs#63626 Reviewed-By: Antoine du Hamel <[email protected]>
Original commit message:
[api] Add V8::GetWasmMemoryReservationSizeInBytes()
When the system does not have enough virtual memory for the wasm
cage, installing the trap handler would cause any code allocating
wasm memory to throw. Therefore it's useful for the embedder to
know when the system doesn't have enough virtual address space
to allocate enough wasm cages and in that case, skip the
trap handler installation so that wasm code can at least work
(even not at the maximal performance).
Node.js previously has a command line option
--disable-wasm-trap-handler to fully disable trap-based bound checks,
this new API would allow it to adapt automatically while keeping the
optimization in the happy path, since it's not always possible for
end users to opt-into disabling trap-based bound checks (for example,
when a VS Code Server is loaded in a remote server for debugging).
Refs: nodejs#62132
Refs: microsoft/vscode#251777
Change-Id: I345c076af2b2b47700e5716b49c3133fdf8a0981
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/7638233
Reviewed-by: Jakob Kummerow <[email protected]>
Reviewed-by: Michael Lippautz <[email protected]>
Commit-Queue: Joyee Cheung <[email protected]>
Reviewed-by: Clemens Backes <[email protected]>
Cr-Commit-Position: refs/heads/main@{#105702}
Refs: v8/v8@bef0d9c
Co-authored-by: Joyee Cheung <[email protected]>
PR-URL: nodejs#62132
Backport-PR-URL: nodejs#64338
Refs: microsoft/vscode#251777
Refs: https://chromium-review.googlesource.com/c/v8/v8/+/7638233
Signed-off-by: Joyee Cheung <[email protected]>
Reviewed-By: Richard Lau <[email protected]>
PR-URL: nodejs#62132 Backport-PR-URL: nodejs#64338 Refs: microsoft/vscode#251777 Refs: https://chromium-review.googlesource.com/c/v8/v8/+/7638233 Signed-off-by: Joyee Cheung <[email protected]> Reviewed-By: Richard Lau <[email protected]>
PR-URL: nodejs#60798 Backport-PR-URL: nodejs#63659 Signed-off-by: Marco Ippolito <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
PR-URL: nodejs#60798 Backport-PR-URL: nodejs#63659 Signed-off-by: Marco Ippolito <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
PR-URL: nodejs#61610 Backport-PR-URL: nodejs#63659 Signed-off-by: Marco Ippolito <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
Blob.prototype.stream() registered a wakeup callback on the underlying source's start() and never released it. The strong Reader::wakeup_ handle kept the reader -- and through it the blob's DataQueue and backing store -- reachable as a GC root, so the source buffer leaked on every stream() call. On Node 26+, streaming a 1 MiB blob 300 times retained ~300 MiB in process.memoryUsage().arrayBuffers while the V8 heap stayed small. Register the wakeup lazily in pull() and clear it on every terminal or idle path (EOS, error, cancel, backpressure), mirroring the cleanup already done by the async iterator path. The strong handle now only lives while a pull is in flight, so the reader and its backing store become collectable once the stream finishes, errors, is cancelled, or goes idle under backpressure. Fixes: nodejs#63574 Signed-off-by: semimikoh <[email protected]> PR-URL: nodejs#63577 Fixes: nodejs#63574 Reviewed-By: James M Snell <[email protected]> (cherry picked from commit 243905a)
Backport prerequisite for the previous commit (backport of nodejs#63577). The Blob.stream() leak fix clears the reader's wakeup handle by calling reader.setWakeup(undefined) on every terminal/idle path. On main the C++ Blob::Reader::SetWakeup already tolerates an undefined argument (resetting the strong wakeup_ handle), but that guard is not present on v24.x -- it landed incidentally in the large QUIC implementation commit cf91d18 (nodejs#62876), which is not itself being backported. Extract only the minimal node_blob.cc SetWakeup hunk from that commit so the JS fix works on v24.x. Without it, setWakeup(undefined) aborts with `Assertion failed: args[0]->IsFunction()` at src/node_blob.cc. The NotifyPull(fin)/pull_pending_ coalescing from the same upstream commit is QUIC-specific, not required by the leak fix, and is intentionally omitted. Refs: nodejs#63577 Refs: nodejs#62876 Signed-off-by: Gabe Bryk <[email protected]>
gabrielbryk
force-pushed
the
backport-63577-to-v24.x
branch
from
July 22, 2026 18:25
34a4610 to
2aa101b
Compare
Contributor
|
It's already on the staging branch |
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.
Backport of #63577 to v24.x. It doesn't cherry-pick cleanly on its own: the
JS fix clears the reader's wakeup handle with
reader.setWakeup(undefined),but on v24.x the C++
Blob::Reader::SetWakeupstill asserts a functionargument. The guard that makes it accept
undefinedonly landed as part ofthe QUIC commit cf91d18 (#62876), which isn't on this line, so a plain
cherry-pick builds but aborts the first time a stream reaches a terminal/idle
path:
The second commit extracts only that four-line
node_blob.ccguard from#62876; the rest of that commit (the
NotifyPull(fin)/pull_pending_coalescing) is QUIC-specific and not needed here. It could instead be done as
a prerequisite backport of #62876, or folded into the cherry-pick, if a
reviewer prefers.
parallel/test-blob*, including the newtest-blob-stream-gc.jsfrom #63577,passes on a local build; the #63574 reproducer holds
arrayBuffersflat where24.16.0 leaks the source buffer on every stream.