Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/test-shared.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,20 +141,23 @@ jobs:
include:
- runner: ubuntu-24.04
system: x86_64-linux
# Exercise the trace-event code against a perfetto-enabled V8.
perfetto: true
# built separately in build-aarch64-linux-v8
# - runner: ubuntu-24.04-arm
# system: aarch64-linux
- runner: macos-15-intel
system: x86_64-darwin
- runner: macos-latest
system: aarch64-darwin
name: '${{ matrix.system }}: with shared libraries'
name: '${{ matrix.system }}: with shared libraries${{ matrix.perfetto && '' and perfetto'' || '''' }}'
uses: ./.github/workflows/build-shared.yml
with:
runner: ${{ matrix.runner }}
with-sccache: ${{ github.base_ref == 'main' || github.ref_name == 'main' }}
extra-nix-flags: |
--arg useSeparateDerivationForV8 true \
${{ matrix.perfetto && '--arg withPerfetto true \' || '\' }}
${{ endsWith(matrix.system, '-darwin') && '--arg withAmaro false --arg withLief false --arg withSQLite false --arg withFFI false --arg extraConfigFlags ''["--without-inspector" "--without-node-options"]'' \' || '\' }}
secrets:
CACHIX_AUTH_TOKEN: ${{ secrets.CACHIX_AUTH_TOKEN }}
Expand Down
4 changes: 2 additions & 2 deletions benchmark/misc/trace.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ const bench = common.createBenchmark(main, {
});

const {
TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN: kBeforeEvent,
TRACE_EVENT_PHASE_BEGIN: kBeginEvent,
} = common.binding('constants').trace;

function doTrace(n, trace) {
bench.start();
for (let i = 0; i < n; i++) {
trace(kBeforeEvent, 'foo', 'test', 0, 'test');
trace(kBeginEvent, 'foo', 'test', 0, 'test');
}
bench.end(n);
}
Expand Down
18 changes: 18 additions & 0 deletions doc/api/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4697,6 +4697,23 @@
`res.writableFinished` to confirm whether the response was written
successfully before the response closed.

### DEP0208: `Server.prototype._listen2`

<!-- YAML
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/64794

Check warning on line 4705 in doc/api/deprecations.md

View workflow job for this annotation

GitHub Actions / lint-pr-url

pr-url doesn't match the URL of the current PR.
description: Runtime deprecation.
-->

Type: Runtime

`net.Server.prototype._listen2` is an undocumented alias for an internal
function that sets up the listening handle. It is kept only so that code
replacing it keeps being called by [`server.listen()`][], and it will be
removed in a future version of Node.js. Use [`server.listen()`][] instead of
calling or overriding `_listen2`.

[DEP0142]: #dep0142-repl_builtinlibs
[DEP0156]: #dep0156-aborted-property-and-abort-aborted-event-in-http
[NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
Expand Down Expand Up @@ -4814,6 +4831,7 @@
[`response.writableEnded`]: http.md#responsewritableended
[`response.writableFinished`]: http.md#responsewritablefinished
[`script.createCachedData()`]: vm.md#scriptcreatecacheddata
[`server.listen()`]: net.md#serverlisten
[`setInterval()`]: timers.md#setintervalcallback-delay-args
[`setTimeout()`]: timers.md#settimeoutcallback-delay-args
[`socket.bufferSize`]: net.md#socketbuffersize
Expand Down
7 changes: 4 additions & 3 deletions doc/api/ffi.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,17 @@ FFI signatures use string type names.
Supported type names:

* `void`
* `char`
* `i8`, `int8`
* `u8`, `uint8`, `bool`, `char`
* `u8`, `uint8`, `bool`
* `i16`, `int16`
* `u16`, `uint16`
* `i32`, `int32`
* `u32`, `uint32`
* `i64`, `int64`
* `u64`, `uint64`
* `f32`, `float`
* `f64`, `double`
* `f32`, `float`, `float32`
* `f64`, `double`, `float64`
* `pointer`, `ptr`
* `string`, `str`
* `buffer`
Expand Down
13 changes: 13 additions & 0 deletions doc/api/stream.md
Original file line number Diff line number Diff line change
Expand Up @@ -3120,6 +3120,19 @@ console.log(res); // prints 'HELLOWORLD'
For convenience, the [`readable.compose(stream)`][] method is available on
{Readable} and {Duplex} streams as a wrapper for this function.

### `stream.isDestroyed(stream)`

<!-- YAML
added:
- v19.9.0
- v18.17.0
-->

* `stream` {Readable|Writable|Duplex}
* Returns: {boolean|null} - Only returns `null` if `stream` is not a valid `Readable`, `Writable` or `Duplex`.

Returns whether the stream has been destroyed.

### `stream.isErrored(stream)`

<!-- YAML
Expand Down
22 changes: 22 additions & 0 deletions lib/ffi.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ const {
} = require('internal/ffi-shared-buffer');

const {
markFastLibraryClosed,
wrapWithRawPointerConversions,
} = require('internal/ffi/fast-api');

Expand Down Expand Up @@ -100,6 +101,27 @@ function wrapFFIFunction(rawFn, owner) {

const rawGetFunction = DynamicLibrary.prototype.getFunction;
const rawGetFunctions = DynamicLibrary.prototype.getFunctions;
const rawClose = DynamicLibrary.prototype.close;

function close() {
const result = FunctionPrototypeCall(rawClose, this);
markFastLibraryClosed(this);
return result;
}

ObjectDefineProperty(DynamicLibrary.prototype, 'close', {
__proto__: null,
configurable: true,
value: close,
writable: true,
});

ObjectDefineProperty(DynamicLibrary.prototype, SymbolDispose, {
__proto__: null,
configurable: true,
value: close,
writable: true,
});

DynamicLibrary.prototype.getFunction = function getFunction(name, signature) {
const raw = FunctionPrototypeCall(rawGetFunction, this, name, signature);
Expand Down
1 change: 1 addition & 0 deletions lib/internal/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1234,6 +1234,7 @@ E('ERR_FEATURE_UNAVAILABLE_ON_PLATFORM',
'The feature %s is unavailable on the current platform' +
', which is being used to run Node.js',
TypeError);
E('ERR_FFI_LIBRARY_CLOSED', 'Library is closed', Error);
E('ERR_FS_CP_DIR_TO_NON_DIR',
'Cannot overwrite non-directory with directory', SystemError);
E('ERR_FS_CP_EEXIST', 'Target already exists', SystemError);
Expand Down
37 changes: 33 additions & 4 deletions lib/internal/ffi/fast-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const {
NumberIsInteger,
ObjectDefineProperty,
ReflectApply,
SafeWeakMap,
StringPrototypeIncludes,
TypeError,
} = primordials;
Expand All @@ -25,9 +26,16 @@ const {
kFastBufferInvoke,
} = internalBinding('ffi');

const {
codes: {
ERR_FFI_LIBRARY_CLOSED,
},
} = require('internal/errors');

const U64_MAX = 0xFFFFFFFFFFFFFFFFn;
const I64_MAX = 0x7FFFFFFFFFFFFFFFn;
const I64_MIN = -0x8000000000000000n;
const fastLibraryStates = new SafeWeakMap();

// These ranges mirror ToFFIArgument in src/ffi/types.cc. V8's Fast API
// exposes narrow integers as 32-bit values and uses truncating BigInt
Expand Down Expand Up @@ -202,7 +210,20 @@ function inheritMetadata(wrapper, rawFn, nargs) {
return wrapper;
}

function wrapWithRawPointerConversions(rawFn, argumentTypes, _owner) {
function markFastLibraryClosed(owner) {
const state = fastLibraryStates.get(owner);
if (state !== undefined) {
state.closed = true;
}
}

function throwIfFastLibraryClosed(state) {
if (state.closed) {
throw new ERR_FFI_LIBRARY_CLOSED();
}
}

function wrapWithRawPointerConversions(rawFn, argumentTypes, owner) {
if (rawFn === undefined || rawFn === null) {
return rawFn;
}
Expand All @@ -213,11 +234,14 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, _owner) {
return rawFn;
}

const indexes = getFastArgumentIndexes(argumentTypes);
if (indexes === null) {
return rawFn;
let state = fastLibraryStates.get(owner);
if (state === undefined) {
state = { __proto__: null, closed: false };
fastLibraryStates.set(owner, state);
}

const indexes = getFastArgumentIndexes(argumentTypes) ?? [];

const stringState = {
__proto__: null,
buffers: [],
Expand All @@ -233,6 +257,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, _owner) {
const fastBufferInvoke = needsPointerLikeConversion(t0) ?
rawFn[kFastBufferInvoke] : undefined;
wrapper = function(a0) {
throwIfFastLibraryClosed(state);
if (arguments.length !== 1) {
throwFFIArgCountError(1, arguments.length);
}
Expand Down Expand Up @@ -262,6 +287,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, _owner) {
const t0 = argumentTypes[0];
const t1 = argumentTypes[1];
wrapper = function(a0, a1) {
throwIfFastLibraryClosed(state);
if (arguments.length !== 2) {
throwFFIArgCountError(2, arguments.length);
}
Expand All @@ -283,6 +309,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, _owner) {
const t1 = argumentTypes[1];
const t2 = argumentTypes[2];
wrapper = function(a0, a1, a2) {
throwIfFastLibraryClosed(state);
if (arguments.length !== 3) {
throwFFIArgCountError(3, arguments.length);
}
Expand All @@ -300,6 +327,7 @@ function wrapWithRawPointerConversions(rawFn, argumentTypes, _owner) {
};
} else {
wrapper = function(...args) {
throwIfFastLibraryClosed(state);
if (args.length !== nargs) {
throwFFIArgCountError(nargs, args.length);
}
Expand Down Expand Up @@ -332,5 +360,6 @@ module.exports = {
convertPointerArg,
hasPointerMemoryArg,
hasStringPointerArg,
markFastLibraryClosed,
wrapWithRawPointerConversions,
};
20 changes: 9 additions & 11 deletions lib/internal/process/pre_execution.js
Original file line number Diff line number Diff line change
Expand Up @@ -691,20 +691,18 @@ function initializePermission() {
ObjectFreeze(require('path'));
const { has, drop } = require('internal/process/permission');
const warnFlags = [
'--allow-addons',
'--allow-child-process',
'--allow-inspector',
'--allow-wasi',
'--allow-worker',
{ flag: '--allow-addons', enabled: true, code: 'PERM0001' },
{ flag: '--allow-child-process', enabled: true, code: 'PERM0002' },
{ flag: '--allow-ffi', enabled: process.config.variables.node_use_ffi, code: 'PERM0003' },
{ flag: '--allow-inspector', enabled: true, code: 'PERM0004' },
{ flag: '--allow-wasi', enabled: true, code: 'PERM0005' },
{ flag: '--allow-worker', enabled: true, code: 'PERM0006' },
];
if (process.config.variables.node_use_ffi) {
warnFlags.splice(2, 0, '--allow-ffi');
}
for (const flag of warnFlags) {
if (getOptionValue(flag)) {
for (const { flag, enabled, code } of warnFlags) {
if (enabled && getOptionValue(flag)) {
process.emitWarning(
`The flag ${flag} must be used with extreme caution. ` +
'It could invalidate the permission model.', 'SecurityWarning');
'It could invalidate the permission model.', 'SecurityWarning', code);
}
}
const warnCommaFlags = [
Expand Down
33 changes: 26 additions & 7 deletions lib/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ const {
const { isUint8Array } = require('internal/util/types');
const { queueMicrotask } = require('internal/process/task_queues');
const {
deprecate,
guessHandleType,
isWindows,
kEmptyObject,
Expand Down Expand Up @@ -2357,7 +2358,27 @@ function setupListenHandle(address, port, addressType, backlog, fd, flags) {
this);
}

Server.prototype._listen2 = setupListenHandle; // legacy alias
// Legacy alias for `setupListenHandle`, kept around only because it is an
// undocumented monkeypatch point. Nothing in core calls it unless it has been
// overridden, see `callSetupListenHandle`.
const legacyListen2 = deprecate(
setupListenHandle,
'Server.prototype._listen2 is deprecated. Use Server.prototype.listen() instead.',
'DEP0208');
Server.prototype._listen2 = legacyListen2;

// Set up the listen handle, going through `_listen2` when userland replaced it
// so that the monkeypatch keeps taking effect (DEP0208). Servers that did not
// touch `_listen2` must not trigger the deprecation warning.
function callSetupListenHandle(server, address, port, addressType, backlog,
fd, flags) {
if (server._listen2 !== legacyListen2) {
server._listen2(address, port, addressType, backlog, fd, flags);
return;
}
FunctionPrototypeCall(setupListenHandle, server, address, port, addressType,
backlog, fd, flags);
}

// A listening TCP Server can be transferred to another thread, which moves the
// underlying listening socket (and its pending accept queue) to that thread's
Expand Down Expand Up @@ -2431,9 +2452,8 @@ function listenInCluster(server, address, port, addressType,

if (cluster.isPrimary || exclusive) {
// Will create a new handle
// _listen2 sets up the listened handle, it is still named like this
// to avoid breaking code that wraps this method
server._listen2(address, port, addressType, backlog, fd, flags);
callSetupListenHandle(server, address, port, addressType, backlog, fd,
flags);
return;
}

Expand Down Expand Up @@ -2467,9 +2487,8 @@ function listenInCluster(server, address, port, addressType,
}
// Reuse primary's server handle
server._handle = handle;
// _listen2 sets up the listened handle, it is still named like this
// to avoid breaking code that wraps this method
server._listen2(address, port, addressType, backlog, fd, flags);
callSetupListenHandle(server, address, port, addressType, backlog, fd,
flags);
}
}

Expand Down
4 changes: 3 additions & 1 deletion shell.nix
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
withFFI ? true,
withSSL ? true,
withTemporal ? false,
withPerfetto ? false,
sharedLibDeps ? (
import ./tools/nix/sharedLibDeps.nix {
inherit
Expand Down Expand Up @@ -67,7 +68,8 @@ let
)
"--v8-${if withTemporal then "enable" else "disable"}-temporal-support"
]
++ pkgs.lib.optional (withTemporal && useSharedTemporal) "--shared-temporal_capi";
++ pkgs.lib.optional (withTemporal && useSharedTemporal) "--shared-temporal_capi"
++ pkgs.lib.optional withPerfetto "--with-perfetto";
in
pkgs.mkShell {
inherit nativeBuildInputs;
Expand Down
1 change: 1 addition & 0 deletions src/debug_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ void NODE_EXTERN_PRIVATE FWrite(FILE* file, const std::string& str);
V(MODULE) \
V(MKSNAPSHOT) \
V(SNAPSHOT_SERDES) \
V(PERFETTO) \
V(PERMISSION_MODEL) \
V(PLATFORM_MINIMAL) \
V(PLATFORM_VERBOSE) \
Expand Down
Loading
Loading