Commit Graph
12964 Commits
Author SHA1 Message Date
Filip Skokan 39ba3b5ae6 lib: optimize internal Web IDL dictionaries
Flatten dictionary members at construction while preserving inheritance
order. Skip member scans for nullish inputs without defaults or required
members, and define own descriptor properties to avoid inherited
setters.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65857
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2026-09-08 15:20:15 +00:00
Guy Bedford f955c20dd1 net: support sending net.BoundSocket to threads and child processes
This adds support for transferring net.BoundSocket instances to other
threads via the worker_threads postMessage() transfer list, and for
sending them to child processes as the sendHandle argument of
subprocess.send(), following on from the BoundSocket introduction.

A BoundSocket reserves a port synchronously at construction time.
Making it transferable means a port can be reserved on one thread or
process and the bound (but not yet listening or connected) TCP handle
handed off to another to listen or connect on, without racing on the
bind.

For threads, BoundSocket implements kTransfer/kTransferList/
kDeserialize, moving the underlying TCP handle with the same mechanism
used for net.Socket and net.Server transfer. For child processes, the
handleConversion entry reuses the same transfer protocol on the
sending side and the same _TransferredBoundSocket deserialization path
on the receiving side; the underlying transport is that of cluster's
shared-handle scheduling: SCM_RIGHTS on Unix and WSADuplicateSocket on
Windows, both of which carry bind state.

In both cases the source instance is left in the adopted state:
address(), fd() and close() throw ERR_SOCKET_HANDLE_ADOPTED. Transfer
requires an un-adopted, open TCP handle, otherwise
ERR_WORKER_HANDLE_NOT_TRANSFERABLE is thrown; pipe (path) binds are
not transferable and throw ERR_INVALID_HANDLE_TYPE when sent over IPC.
On the receiving side the local address is re-derived from the handle
rather than trusted from serialized state.

Signed-off-by: Guy Bedford <guybedford@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/64725
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-08 16:05:22 +02:00
Filip Skokan 51cb9f46a5 crypto: validate the limit of PBKDF2 iterations
Reject iteration counts outside of OpenSSL supported range

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65704
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
2026-09-08 12:54:46 +00:00
Filip Skokan 271833006c crypto: use primordials in HKDF info validation
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65704
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
2026-09-08 12:54:45 +00:00
Philipp Dunkel 2d9c861a15 vfs: align virtual file handles with open(2)
A file descriptor obtained on a mounted path answers several `node:fs`
calls differently from one on a real file, in both providers:

* `writeFileSync(path, data, { flag: 'r+' })` replaces the whole file
  instead of overwriting bytes from offset 0 and keeping the tail.
* Numeric open flags are mapped by treating any write-ish bit as "w":
  `O_WRONLY` alone truncates, and `O_RDONLY | O_CREAT` opens the file
  write-only and truncates it.
* A handle opened with "a+" starts its read offset at the end of the
  file, so the first read returns nothing; O_APPEND only affects writes.

The ZipProvider handle additionally:

* throws EISDIR instead of EBADF when reading a write-only handle or
  writing a read-only one;
* leaves stale bytes in place when `ftruncate` grows a file that was
  previously shrunk, where real files read back as zeros;
* rejects a BigInt `position` with a TypeError from mixing number and
  BigInt arithmetic.

This adds a test that runs the same sequence of calls against a memory
mount and a ZIP mount and expects the real-fs result, so every
divergence shows up as its own failing case.

Proposed solution: decode numeric flags bit by bit (O_TRUNC decides
truncation, O_CREAT decides creation, O_WRONLY/O_RDWR decide access)
instead of collapsing them to a flag string; keep the read offset at 0
for append handles and only force writes to the end; make the handle
`writeFile` for non-truncating flags write at offset 0 without
shrinking; in the ZIP handle use EBADF for access-mode violations,
zero-fill on growth in `#doTruncate`, and coerce `position` with
`Number()` as the memory handle does.

Signed-off-by: Philipp Dunkel <pip@pipobscure.com>
PR-URL: https://github.com/nodejs/node/pull/65854
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-09-08 11:35:41 +00:00
Filip Skokan 70458d593d lib: validate sequence iterator objects
Reject primitive iterator factory results before accessing next, as
required by GetIteratorFromMethod.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65844
Reviewed-By: Jason Zhang <xzha4350@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com>
2026-09-08 08:50:33 +00:00
Filip Skokan 0a9225dd16 lib: use Web IDL interface brand checks
Use explicit brand predicates for interface conversion instead of
prototype ancestry. Update CryptoKey and AbortSignal together with the
shared converter contract.

Read internal AbortSignal state during composition. Preserve genuine
signals after prototype changes without invoking shadowed getters.

Signed-off-by: Filip Skokan <panva.ip@gmail.com>
Assisted-by: GitHub Copilot
PR-URL: https://github.com/nodejs/node/pull/65846
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
2026-09-08 08:50:21 +00:00
Matteo Collina b113d09c71 stream: create write request objects lazily
Every stream write created a WriteWrap JS object up front, even though
most writes complete synchronously via uv_try_write() and never use it.

Let stream_base_commons pass null instead of a request object.
StreamBase::Write() already creates the wrap object only when the write
does not complete synchronously; return that object to JS (which
attaches oncomplete/callback to it) and a plain error code otherwise.

Writes that complete synchronously now cross the JS/C++ boundary once
and allocate nothing. Callers that pass in a request object
(child_process IPC, webstreams adapters) behave as before.

Since Http2Stream::DoWrite() can invoke the completion callback
synchronously - before JS has attached oncomplete - such completions
are now recorded on the request object's writeStatus field and replayed
by stream_base_commons after dispatch. This also replaces a Has() plus
name-based MakeCallback() pair with a single Get().

Also pre-create the JS fields of WriteWrap instances in the object
template, as was already done for ShutdownWrap, so that they are
in-object properties.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64455
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
2026-09-07 14:49:11 +00:00
Matteo Collina 0f5cb92cf3 stream: allocate stream read buffers from a slab
Read buffers for streams that emit their data to JS were allocated per
read: a 64KB backing store, tracked in a map, and then - since reads
rarely fill the whole buffer - reallocated to the right size and copied.

Allocate read buffers from a 64KB slab instead. Reads reserve the
suggested size from the slab and JS receives a view over the slab's
ArrayBuffer at the read's offset, using the offset mechanism that
onStreamRead already supports. Unused reservation space is rewound when
a read returns less than was reserved, so small reads (e.g. TLS records)
share a slab.

This removes the per-read allocations, the map bookkeeping and the
resize copy.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/64455
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
2026-09-07 14:49:09 +00:00
Philipp Dunkel a701540af3 vfs: answer for unowned paths under reserved root
The module loader manufactures paths under the reserved VFS root that
no layer owns: resolving a mount point as a directory first probes the
sibling names `<mount>.js`, `<mount>.json` and `<mount>.node`, and a
package.json walk-up passes the parents of the mount point. The lookup
declined those because their layer segment is not a plain id, so they
fell through to the native loader and the real file system.

On POSIX that is harmless (ENOTDIR under /dev/null), but on Windows
the root sits under `\\.\nul`, and `\\.\nul\<anything>` opens the NUL
device: libuv reports it as a character device and a read returns
nothing. The loader therefore picked `\\.\nul\vfs\<id>.js` as an
existing file, and the native walk-up above it then read the device as
an empty package.json and failed with ERR_INVALID_PACKAGE_CONFIG for
`\\.\nul\package.json`. Any require() of a mount point hits this on
Windows.

Distinguish "under the root but unowned" from "outside the root" in the
lookup and have every loader override report the former as not found:
stat gives ENOENT, reads and realpath throw ENOENT, the package.json
lookups return their "no package.json" results, and upward walks stop
at the reserved root. Paths outside the root still go to the native
loader as before.

Refs: https://github.com/nodejs/node/pull/65748
Signed-off-by: Philipp Dunkel <pip@pipobscure.com>
PR-URL: https://github.com/nodejs/node/pull/65814
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-07 14:48:56 +00:00
Y1D7NG 9f7ae86d8b stream: destroy source when map iterator closes early
Fixes: https://github.com/nodejs/node/issues/64261
Signed-off-by: y1d7ng <y1d7ng@yeah.net>
PR-URL: https://github.com/nodejs/node/pull/64264
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-09-07 12:35:04 +00:00
James M Snell 8fb89abb8d src,lib: add util.markPromiseAsHandled
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65805
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
Reviewed-By: LiviaMedeiros <livia@cirno.name>
2026-09-07 11:42:09 +00:00
Shelley Vohr 29667e046b fs: copy directory trees for fs.cp() on the thread pool
fs.cp() and fs.promises.cp() walked the tree in JavaScript with several
thread pool round trips per entry (opendir batches, two stat()s, the
copyFile(), a chmod()), all awaited in sequence: a 2 100-file tree took
~215 ms with ~110 ms of that on the main thread, against ~36 ms for
fs.cpSync(), which copies the tree in C++ when no filter is given.

Factor that C++ walk into CopyDirRecursive(), which records the error
instead of throwing so that it can run on any thread, and run it as one
ThreadPoolWork request (CpDirJob) for fs.cp()/fs.promises.cp() when
the destination directory does not exist yet and nothing has to run per
entry (no filter, no dereference, permission model off). Copying into
an existing tree keeps the JavaScript walk and its rules for what may
already be there. The same tree now takes ~30 ms with under 1 ms on the
main thread.

For that job the walk follows the JavaScript walk's rules rather than
cpSync's: it creates every directory with mkdir() and every file with
an exclusive uv_fs_copyfile() (honouring the copyFile() mode flags) and
fails with EEXIST if anything has appeared in their place since the
JavaScript check, so it never opens or follows something it did not
create; sockets, FIFOs and unknown entries are reported back to
JavaScript, which rejects them with the same SystemErrors as before;
relative link targets are made absolute lexically as path.resolve()
does. cpSync keeps merging into existing directories, skipping special
files and canonicalizing link targets.

The walk now uses the error_code overloads of std::filesystem throughout
(directory iteration included), so an unreadable directory inside the
tree is reported as EACCES by both cp() and cpSync() instead of
terminating the process, which cpSync() has done since the walk moved
to C++. Filesystem errors raised inside the walk keep their codes, with
'cp' or 'copyfile'/'mkdir' as the syscall. With preserveTimestamps the
walk stamps each directory it filled, root included, so cp() keeps
preserving directory times and cpSync() without a filter now does too.
Both file copies set the destination's mode before writing the data,
which clears setuid and setgid, so the walk puts the source mode back
after each file it copied; the JavaScript walk already chmod()s there.

Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65488
Refs: https://github.com/nodejs/node/pull/58461
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Aviv Keller <me@aviv.sh>
Reviewed-By: Jake Yuesong Li <jake.yuesong@gmail.com>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-09-07 05:26:21 +00:00
Shelley Vohr 48c90fffb7 src: support building with the V8 sandbox
With V8_ENABLE_SANDBOX every ArrayBuffer backing store has to be
allocated inside the sandbox, so memory that Node.js or a library
allocated itself cannot be wrapped and has to be copied in. Several
places already special-cased this, each with its own #ifdef, but a
build with the sandbox enabled still failed to compile
(`kMaxSafeBufferSizeForSandbox`), aborted in `crypto.randomUUID()`
(`SecureBuffer` was UNREACHABLE) and threw from every caller of the
malloc-owning `Buffer::New()` (v8.serialize, string transcoding, IPC,
the public `Buffer::New(isolate, data, length)`), and trace_events,
SEA assets and FFI still wrapped outside memory unconditionally.

Add `AdoptIntoBackingStore()`, which wraps the memory as before in
regular builds and copies it into an isolate-allocated backing store,
running the deleter right away, when the sandbox is enabled, and use it
at all of those sites so the #ifdef lives in one place. The trace
category flag cannot be copied since JS polls it, so under the sandbox
`getCategoryEnabledBuffer()` returns nothing and lib falls back to
`isTraceCategoryEnabled()`; FFI zero-copy views throw
ERR_OPERATION_FAILED there for the same reason.

Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/62237
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
2026-09-07 05:10:02 +00:00
Hamid Reza Ghavami 1f53d7ee3f fs: return Buffer from mkdtemp when prefix is a Buffer
Signed-off-by: Hamid Reza Ghavami <hamidr.ghavami@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/64397
Fixes: https://github.com/nodejs/node/issues/58795
Reviewed-By: René <contact.9a5d6388@renegade334.me.uk>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
2026-09-06 23:02:02 +00:00
James M Snell 7aba44d4ac stream: use webidl validation semantics for args
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:36:06 +00:00
James M Snell 5ada066715 stream: ensure that stateful transforms preserve this
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:36:05 +00:00
James M Snell 33f85fee74 stream: fix nested async flushing with infinite sources
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:36:04 +00:00
James M Snell 60b8f285f6 stream: ensure from() observes returned rejecting promise correctly
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:36:03 +00:00
James M Snell 6e1789a3ce stream: apply source normalization once at call time
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:36:02 +00:00
James M Snell 7fafadf3ce stream: make consumer signals on longer alter source precedence
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:36:01 +00:00
James M Snell 7089049a09 stream: make pipeTo source normalization independent of Writer
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:36:00 +00:00
James M Snell 1ed73da6a0 stream: pre-aborted pipeTo now applies dest failure handling
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:35:59 +00:00
James M Snell e6332d6175 stream: ensure pre-existing writes drain before EOF and end() waits
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:35:58 +00:00
James M Snell 57e0f33ebc stream: ensure async dispoal after endSync awaits for drain
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:35:57 +00:00
James M Snell 3c8f77f15d stream: ensure factory signals remain active through closing
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:35:55 +00:00
James M Snell 7b61c62a3f stream: canWrite and ondrain now reflect physical capacity
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65658
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
2026-09-06 04:35:55 +00:00
Filip Skokan 2d2250529d crypto: add Hybrid KEMs to Web Cryptography
Signed-off-by: Filip Skokan <panva.ip@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65759
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
2026-09-05 10:42:52 +00:00
James M Snell d011d0a701 lib: fixup node:bench handling of --require option
Signed-off-by: James M Snell <jasnell@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65631
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-05 02:49:06 +00:00
James M Snell dd70a25c20 lib,benchmark: address multiple review issues
Refs: https://github.com/nodejs/node/pull/65606#discussion_r3887305271
Refs: https://github.com/nodejs/node/pull/65606#discussion_r3887305272
Refs: https://github.com/nodejs/node/pull/65606#discussion_r3887305275
PR-URL: https://github.com/nodejs/node/pull/65631
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-05 02:49:05 +00:00
James M Snell b00bd40525 lib: improve diagnostic message support
Support serializable context.diagnostic messages and
optionally listen to diagnostic_channel messages

Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65631
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-05 02:49:04 +00:00
James M Snell 0cd23edced lib: have runFile honor permissions and accept URL/Buffer paths
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65631
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-05 02:49:03 +00:00
James M Snell b6ade12c7d lib: add runFile api to node:bench
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65631
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-05 02:49:02 +00:00
James M Snell 12d7bb9262 lib: add context.diagnostic api to node:bench
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65631
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-05 02:49:01 +00:00
James M Snell 09de6104f2 lib: add bench:plan event to node:bench
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65631
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-05 02:48:59 +00:00
James M Snell 5a346e0812 lib: improve node:bench stream handling
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65631
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-05 02:48:56 +00:00
James M Snell 838baeba7f lib: add runId, fileRunId, entryFile, namePath to node:bench
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65631
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-05 02:48:55 +00:00
Issac f85bb5ed78 permission: do not enforce fs and addons in audit mode
--permission-audit is documented to perform permission checks without
denying access, publishing each violation through the diagnostics
channel while execution continues. Three code paths still enforced:

* fs.lstat() and fs.symlink() are checked in the JavaScript layer,
  which threw ERR_ACCESS_DENIED without consulting audit mode. The
  isAuditMode() helper introduced for ffi was never wired into fs.
* Addon loading was disabled upfront in Environment setup, so
  process.dlopen() failed with ERR_DLOPEN_DISABLED before reaching
  the audit-aware permission check, and no audit event was published.

Skip the throw in the JavaScript checks when audit mode is on, keeping
the permission.has() call first so the diagnostics channel event is
still published. Leave native addons enabled in audit mode while still
applying the kAddon scope, so DLOpen() publishes the denial through
the channel and continues to the regular loading path. This also
covers the worker path, which inherits kNoNativeAddons from the same
option.

Each fs API carries its own copy of the check in its sync, callback
and promise flavour, so the regression test exercises all six call
sites, asserting the --permission enforce behaviour as a control.

Fixes: https://github.com/nodejs/node/issues/65419
Refs: https://github.com/nodejs/node/pull/63047
Assisted-by: claude:opus-5
Signed-off-by: Ji Hoon Kang <ivory.ma9ic@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65659
Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
2026-09-04 22:22:10 +00:00
Matteo Collina 68e0ce0bde stream: skip unobserved 'readable' emission at EOF
When a stream reaches its end via push(null) while nobody is observing
it (no 'readable' listener, not flowing, no pending readable need), do
not schedule the deferred 'readable' emission: it fires into the void
and costs a tick. Record that the end-of-stream notification is owed
instead; attaching a 'readable' listener later emits it, and read()
and resume() reach the end of the stream on their own.

As a side effect, a 'readable' listener attached more than a tick
after an unobserved end now receives the owed 'readable' before 'end',
where it previously received only 'end'.

For an HTTP server this removes one nextTick and one dead emit per
request whose body the handler never reads.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/65749
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-04 19:57:57 +00:00
Philipp Dunkel ee36353428 vfs: load native addons from a mounted file system
A native addon inside a virtual file system could not be require()d:
dlopen() and LoadLibrary() open a shared object by path, and a VFS path
has no inode for them to open.

Read the addon's bytes from the VFS and load them from a private,
self-cleaning image instead, using the smallest on-disk footprint each
platform allows: on Linux an anonymous memfd loaded through
/proc/self/fd, so the bytes never reach the file system; on other POSIX
platforms a file in a 0700 mkdtemp() directory, unlinked right after
loading, with the mapping keeping it alive; on Windows a temp file
opened FILE_FLAG_DELETE_ON_CLOSE whose handle is held until exit.

This is internal. process.dlopen() keeps its documented
(module, filename[, flags]) signature and ignores anything further; the
bytes are passed to a dlopenBinary() reachable only through the
process_methods binding, which the VFS hook calls for VFS paths. Addons
on the real file system are untouched and load directly.

Signed-off-by: Philipp Dunkel <pip@pipobscure.com>
PR-URL: https://github.com/nodejs/node/pull/65680
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-04 16:48:33 +00:00
Matteo Collina dd0f2032e6 http: fast-forward teardown of unread messages
When a response finishes and the incoming message was fully received
but never read, _dump() no longer goes through resume(): read(0) at
EOF schedules the 'end' emission directly, skipping the resume_ tick,
the 'resume' emit and the flow() machinery.

Reduces the per-request nextTick count of a hello-world HTTP server
from 7 to 6 and CPU per request by ~4%.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/65732
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Tim Perry <pimterry@gmail.com>
2026-09-04 18:13:16 +02:00
Shelley Vohr ddc0a0aa28 worker: start worker threads from the built-in snapshot
Every `new Worker()` runs the whole internal bootstrap (realm, node, web
exposure, thread and process-state switches) in its fresh isolate,
compiling ~80 builtins with the code cache; only the main thread
deserializes its principal context from the built-in snapshot. That
bootstrap is about half of a worker's cold start.

The bootstrapped principal context in the snapshot is nearly
thread-neutral: the worker-side switch scripts (is_not_main_thread,
does_not_own_process_state) are written as overrides of the main-thread
ones, and the per-thread values of the `worker` binding were the only
thread-specific data baked into the context. Let a worker deserialize
that same context and EnvSerializeInfo and apply the two worker-side
switches on top:

- worker binding: threadId, threadName, isMainThread, isInternalThread,
  ownsProcessState and resourceLimits become lazy properties of the
  per-isolate template, computed from the Environment on first read.
- CreateEnvironment(): when a worker (its IsolateData has a Worker)
  passes an empty context, deserialize kNodeMainContextIndex and run
  internal/bootstrap/switches/is_not_main_thread and, unless the worker
  owns process state, does_not_own_process_state after
  InitializeMainContext().
- Worker::Run(): take that path when the embedded built-in snapshot is
  in use (not an embedder's or a --snapshot-blob one, which has run
  application code), browser globals are not disabled and
  --no-worker-snapshot was not given; otherwise bootstrap as before.
- is_not_main_thread.js: also delete _debugPause and the profiler idle
  notifier helpers that is_main_thread.js installs.
- pre_execution: run the snapshot's deserialize callbacks (Buffer pool,
  default resolver, cached cwd) on worker threads too, now that a worker
  can come from a snapshot.
- --[no-]worker-snapshot per-isolate option, documented.

Sequential new Worker() -> 'online' -> terminate goes from ~20.9 ms to
~10.3 ms per worker on x64 Linux; --no-worker-snapshot restores the old
number.

Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65336
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2026-09-04 13:28:27 +00:00
Matteo Collina 7551e1d906 stream: avoid per-chunk promises in webstream adapters
Readable.fromWeb() and the read side of Duplex.fromWeb() allocated a
promise, a read-result object, and two reaction closures for every
chunk through reader.read(); a single reused read request now delivers
chunks through readableStreamDefaultReaderRead() instead, forwarding
each chunk in a microtask to preserve the delivery order relative to
errors and destroy.

Writable.fromWeb() and the write side of Duplex.fromWeb() paid two
derived promises off writer.ready plus the writer.write() promise and a
fresh closure pair per chunk; a single shared write request now
dispatches chunks directly and settles the node callback, with failures
delivered in a microtask.

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/65548
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-04 06:48:17 +00:00
Christian Aurich a1bfce980c errors: validate constructor name
determineSpecificType() checks for a usable constructor name with
`'name' in value.constructor`. That accepts an empty name, and the `in`
operator requires its right-hand side to be an object.

Anonymous classes own a `name` that is the empty string, so they produce
messages ending in a dangling "Received an instance of ". A truthy
primitive `constructor` reaches the `in` operator and throws while the
message is being built, so ERR_INVALID_ARG_TYPE is replaced by a
TypeError carrying no `code`. The latter is reachable from untrusted
input, since `constructor` is an ordinary JSON key.

The check changed in #49696, while this function was rewritten as a
switch. That pull request updated test/common's invalidArgTypeHelper to
match its deliberate change to the `function` branch, but left the
helper's `object` branch on the original truthy check, so the two have
disagreed since.

Read `constructor` and its `name` once and use the name only when it is
a non-empty string. Requiring a string also stops meaningless names from
being interpolated: 42 currently yields "an instance of 42", and a
symbol name throws outright. The current check reads `constructor` three
times, which an accessor can observe.

Move the helper to the same check so the two cannot drift apart again.

Signed-off-by: Christian Aurich <christian.aurichzm@gmail.com>
PR-URL: https://github.com/nodejs/node/pull/65607
Refs: https://github.com/nodejs/node/pull/49696
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
2026-09-04 04:45:19 +00:00
James M Snell 7f7bbc8ebe test: improve node:bench test coverage
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65606
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-09-03 15:37:22 +00:00
James M Snell 1b644eac8e lib: add node:bench explicit createRunner
Makes it easier for benchmark tools to build on top of
the bench runner primitives.

Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65606
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-09-03 15:37:21 +00:00
James M Snell 409242ca8c lib: complete the implementation of node:bench and cli
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65606
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-09-03 15:37:21 +00:00
James M Snell bc96423ce4 lib: implement bench/reporters
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65606
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-09-03 15:37:21 +00:00
James M Snell 4d2f7a6f4c lib: implement node:bench
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65606
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-09-03 15:37:21 +00:00
James M Snell 06d23c293c perf_hooks: implement Histogram meanCI API
Signed-off-by: James M Snell <jasnell@gmail.com>
Assisted-by: Opencode
PR-URL: https://github.com/nodejs/node/pull/65606
Reviewed-By: Filip Skokan <panva.ip@gmail.com>
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Vinícius Lourenço Claro Cardoso <contact@viniciusl.com.br>
Reviewed-By: Gürgün Dayıoğlu <hey@gurgun.day>
2026-09-03 15:37:21 +00:00