From cd1415c8b29546b7997590359f5a86ccef172bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Sat, 8 Jun 2024 21:11:24 +0000 Subject: [PATCH 01/96] Revert "crypto: make timingSafeEqual faster for Uint8Array" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 0f784c96ba1f41f59b7a54c3177496e789199a68 because it triggers a bug in the V8 version that Node.js 20.x uses. PR-URL: https://github.com/nodejs/node/pull/53390 Reviewed-By: Richard Lau Reviewed-By: Michaël Zasso Reviewed-By: Marco Ippolito Reviewed-By: Benjamin Gruenbaum Reviewed-By: Yagiz Nizipli Reviewed-By: Filip Skokan Reviewed-By: Rafael Gonzaga --- benchmark/crypto/timingSafeEqual.js | 22 ---------------------- src/crypto/crypto_timing.cc | 26 ++------------------------ src/node_external_reference.h | 6 ------ 3 files changed, 2 insertions(+), 52 deletions(-) delete mode 100644 benchmark/crypto/timingSafeEqual.js diff --git a/benchmark/crypto/timingSafeEqual.js b/benchmark/crypto/timingSafeEqual.js deleted file mode 100644 index 475807dba4ea4e..00000000000000 --- a/benchmark/crypto/timingSafeEqual.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -const common = require('../common.js'); -const assert = require('node:assert'); -const { randomBytes, timingSafeEqual } = require('node:crypto'); - -const bench = common.createBenchmark(main, { - n: [1e5], - bufferSize: [10, 100, 200, 2_100, 22_023], -}); - -function main({ n, bufferSize }) { - const bufs = [randomBytes(bufferSize), randomBytes(bufferSize)]; - bench.start(); - let count = 0; - for (let i = 0; i < n; i++) { - const ret = timingSafeEqual(bufs[i % 2], bufs[1]); - if (ret) count++; - } - bench.end(n); - assert.strictEqual(count, Math.floor(n / 2)); -} diff --git a/src/crypto/crypto_timing.cc b/src/crypto/crypto_timing.cc index 103a620d63726f..3d876fc4c3035f 100644 --- a/src/crypto/crypto_timing.cc +++ b/src/crypto/crypto_timing.cc @@ -9,8 +9,6 @@ namespace node { -using v8::FastApiCallbackOptions; -using v8::FastApiTypedArray; using v8::FunctionCallbackInfo; using v8::Local; using v8::Object; @@ -48,32 +46,12 @@ void TimingSafeEqual(const FunctionCallbackInfo& args) { CRYPTO_memcmp(buf1.data(), buf2.data(), buf1.size()) == 0); } -bool FastTimingSafeEqual(Local receiver, - const FastApiTypedArray& a, - const FastApiTypedArray& b, - // NOLINTNEXTLINE(runtime/references) - FastApiCallbackOptions& options) { - uint8_t* data_a; - uint8_t* data_b; - if (a.length() != b.length() || !a.getStorageIfAligned(&data_a) || - !b.getStorageIfAligned(&data_b)) { - options.fallback = true; - return false; - } - - return CRYPTO_memcmp(data_a, data_b, a.length()) == 0; -} - -static v8::CFunction fast_equal(v8::CFunction::Make(FastTimingSafeEqual)); - void Initialize(Environment* env, Local target) { - SetFastMethodNoSideEffect( - env->context(), target, "timingSafeEqual", TimingSafeEqual, &fast_equal); + SetMethodNoSideEffect( + env->context(), target, "timingSafeEqual", TimingSafeEqual); } void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(TimingSafeEqual); - registry->Register(FastTimingSafeEqual); - registry->Register(fast_equal.GetTypeInfo()); } } // namespace Timing diff --git a/src/node_external_reference.h b/src/node_external_reference.h index 17c0b2d7e1a440..a3317d25ad6a96 100644 --- a/src/node_external_reference.h +++ b/src/node_external_reference.h @@ -27,11 +27,6 @@ using CFunctionCallbackWithStrings = bool (*)(v8::Local, const v8::FastOneByteString& input, const v8::FastOneByteString& base); -using CFunctionCallbackWithTwoUint8ArraysFallback = - bool (*)(v8::Local, - const v8::FastApiTypedArray&, - const v8::FastApiTypedArray&, - v8::FastApiCallbackOptions&); using CFunctionWithUint32 = uint32_t (*)(v8::Local, const uint32_t input); using CFunctionWithDoubleReturnDouble = double (*)(v8::Local, @@ -56,7 +51,6 @@ class ExternalReferenceRegistry { V(CFunctionCallbackWithBool) \ V(CFunctionCallbackWithString) \ V(CFunctionCallbackWithStrings) \ - V(CFunctionCallbackWithTwoUint8ArraysFallback) \ V(CFunctionWithUint32) \ V(CFunctionWithDoubleReturnDouble) \ V(CFunctionWithInt64Fallback) \ From d02907ecc4f108eaad89e9a2a92629fde0af3058 Mon Sep 17 00:00:00 2001 From: Ali Hassan Date: Mon, 15 Apr 2024 23:56:01 +0500 Subject: [PATCH 02/96] src: remove misplaced windows code under posix guard in node.cc The V8 WebAssembly trap handler setup for Windows was incorrectly nested within a POSIX conditional compilation block in src/node.cc. This caused the related functions to be effectively non-operational on Windows. The changes involve removing the Windows-specific code from the POSIX section and correctly placing it under the WIN32 check. This fix will ensure that the intended exception handling is active on Windows builds. Fixes: https://github.com/nodejs/node/issues/52404 Refs: https://github.com/nodejs/node/pull/35033 PR-URL: https://github.com/nodejs/node/pull/52545 Reviewed-By: Daeyeon Jeong Reviewed-By: Joyee Cheung --- src/node.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/node.cc b/src/node.cc index 3e4f1b5d730865..f60d8f4f2bf03e 100644 --- a/src/node.cc +++ b/src/node.cc @@ -421,7 +421,7 @@ typedef void (*sigaction_cb)(int signo, siginfo_t* info, void* ucontext); #endif #if NODE_USE_V8_WASM_TRAP_HANDLER #if defined(_WIN32) -static LONG TrapWebAssemblyOrContinue(EXCEPTION_POINTERS* exception) { +static LONG WINAPI TrapWebAssemblyOrContinue(EXCEPTION_POINTERS* exception) { if (v8::TryHandleWebAssemblyTrapWindows(exception)) { return EXCEPTION_CONTINUE_EXECUTION; } @@ -627,13 +627,6 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) { RegisterSignalHandler(SIGTERM, SignalExit, true); #if NODE_USE_V8_WASM_TRAP_HANDLER -#if defined(_WIN32) - { - constexpr ULONG first = TRUE; - per_process::old_vectored_exception_handler = - AddVectoredExceptionHandler(first, TrapWebAssemblyOrContinue); - } -#else // Tell V8 to disable emitting WebAssembly // memory bounds checks. This means that we have // to catch the SIGSEGV/SIGBUS in TrapWebAssemblyOrContinue @@ -649,7 +642,6 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) { CHECK_EQ(sigaction(SIGBUS, &sa, nullptr), 0); #endif } -#endif // defined(_WIN32) V8::EnableWebAssemblyTrapHandler(false); #endif // NODE_USE_V8_WASM_TRAP_HANDLER } @@ -678,6 +670,14 @@ static void PlatformInit(ProcessInitializationFlags::Flags flags) { } #endif // __POSIX__ #ifdef _WIN32 +#ifdef NODE_USE_V8_WASM_TRAP_HANDLER + { + constexpr ULONG first = TRUE; + per_process::old_vectored_exception_handler = + AddVectoredExceptionHandler(first, TrapWebAssemblyOrContinue); + } + V8::EnableWebAssemblyTrapHandler(false); +#endif // NODE_USE_V8_WASM_TRAP_HANDLER if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) { for (int fd = 0; fd <= 2; ++fd) { auto handle = reinterpret_cast(_get_osfhandle(fd)); From 6ea72a53c3c287e17fd618038bfd687c5eadee3f Mon Sep 17 00:00:00 2001 From: Raz Luvaton <16746759+rluvaton@users.noreply.github.com> Date: Wed, 1 May 2024 17:19:57 +0300 Subject: [PATCH 03/96] doc: add test_runner to subsystem PR-URL: https://github.com/nodejs/node/pull/52774 Reviewed-By: Moshe Atlow Reviewed-By: Luigi Pinca Reviewed-By: Yagiz Nizipli Reviewed-By: Marco Ippolito --- doc/contributing/collaborator-guide.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/contributing/collaborator-guide.md b/doc/contributing/collaborator-guide.md index 918acf9e876140..cb311f22ea49c7 100644 --- a/doc/contributing/collaborator-guide.md +++ b/doc/contributing/collaborator-guide.md @@ -847,6 +847,7 @@ might impact an LTS release. | `lib/net` | @bnoordhuis, @indutny, @nodejs/streams | | `lib/repl` | @nodejs/repl | | `lib/{_}stream{*}` | @nodejs/streams | +| `lib/internal/test_runner` | @nodejs/test\_runner | | `lib/timers` | @nodejs/timers | | `lib/util` | @nodejs/util | | `lib/zlib` | @nodejs/zlib | From 56e19e38f3c7c996bbe9605630c079e263c68e05 Mon Sep 17 00:00:00 2001 From: Rafael Gonzaga Date: Wed, 1 May 2024 15:27:29 -0300 Subject: [PATCH 04/96] test: drop test-crypto-timing-safe-equal-benchmarks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/52751 Refs: https://github.com/nodejs/node/issues/38226 Reviewed-By: Marco Ippolito Reviewed-By: Filip Skokan Reviewed-By: Michaël Zasso Reviewed-By: Daniel Lemire Reviewed-By: Richard Lau Reviewed-By: Luigi Pinca Reviewed-By: Rich Trott --- test/pummel/pummel.status | 8 -- ...est-crypto-timing-safe-equal-benchmarks.js | 122 ------------------ 2 files changed, 130 deletions(-) delete mode 100644 test/pummel/test-crypto-timing-safe-equal-benchmarks.js diff --git a/test/pummel/pummel.status b/test/pummel/pummel.status index 589647bcb741fa..fa95696e345bc3 100644 --- a/test/pummel/pummel.status +++ b/test/pummel/pummel.status @@ -12,10 +12,6 @@ test-fs-watch-non-recursive: PASS,FLAKY # https://github.com/nodejs/node/issues/50260 test-structuredclone-jstransferable: PASS,FLAKY -[$system==linux] -# https://github.com/nodejs/node/issues/38226 -test-crypto-timing-safe-equal-benchmarks: PASS,FLAKY - [$system==macos] [$arch==arm || $arch==arm64] @@ -31,7 +27,3 @@ test-heapsnapshot-near-heap-limit: PASS,FLAKY [$system==ibmi] # https://github.com/nodejs/node/issues/39683 test-regress-GH-892: PASS, FLAKY - -[$arch==s390x] -# https://github.com/nodejs/node/issues/38226 -test-crypto-timing-safe-equal-benchmarks: PASS,FLAKY diff --git a/test/pummel/test-crypto-timing-safe-equal-benchmarks.js b/test/pummel/test-crypto-timing-safe-equal-benchmarks.js deleted file mode 100644 index 93c89730f3aaf3..00000000000000 --- a/test/pummel/test-crypto-timing-safe-equal-benchmarks.js +++ /dev/null @@ -1,122 +0,0 @@ -'use strict'; -const common = require('../common'); -if (!common.hasCrypto) - common.skip('missing crypto'); - -if (!common.enoughTestMem) - common.skip('memory-intensive test'); - -const assert = require('assert'); -const crypto = require('crypto'); - -function runOneBenchmark(compareFunc, firstBufFill, secondBufFill, bufSize) { - return eval(` - const firstBuffer = Buffer.alloc(bufSize, firstBufFill); - const secondBuffer = Buffer.alloc(bufSize, secondBufFill); - - const startTime = process.hrtime(); - const result = compareFunc(firstBuffer, secondBuffer); - const endTime = process.hrtime(startTime); - - // Ensure that the result of the function call gets used, so it doesn't - // get discarded due to engine optimizations. - assert.strictEqual(result, firstBufFill === secondBufFill); - - endTime[0] * 1e9 + endTime[1]; - `); -} - -function getTValue(compareFunc) { - const numTrials = 1e5; - const bufSize = 10000; - // Perform benchmarks to verify that timingSafeEqual is actually timing-safe. - - const rawEqualBenches = Array(numTrials); - const rawUnequalBenches = Array(numTrials); - - for (let i = 0; i < numTrials; i++) { - if (Math.random() < 0.5) { - // First benchmark: comparing two equal buffers - rawEqualBenches[i] = runOneBenchmark(compareFunc, 'A', 'A', bufSize); - // Second benchmark: comparing two unequal buffers - rawUnequalBenches[i] = runOneBenchmark(compareFunc, 'B', 'C', bufSize); - } else { - // Flip the order of the benchmarks half of the time. - rawUnequalBenches[i] = runOneBenchmark(compareFunc, 'B', 'C', bufSize); - rawEqualBenches[i] = runOneBenchmark(compareFunc, 'A', 'A', bufSize); - } - } - - const equalBenches = filterOutliers(rawEqualBenches); - const unequalBenches = filterOutliers(rawUnequalBenches); - - // Use a two-sample t-test to determine whether the timing difference between - // the benchmarks is statistically significant. - // https://wikipedia.org/wiki/Student%27s_t-test#Independent_two-sample_t-test - - const equalMean = mean(equalBenches); - const unequalMean = mean(unequalBenches); - - const equalLen = equalBenches.length; - const unequalLen = unequalBenches.length; - - const combinedStd = combinedStandardDeviation(equalBenches, unequalBenches); - const standardErr = combinedStd * Math.sqrt(1 / equalLen + 1 / unequalLen); - - return (equalMean - unequalMean) / standardErr; -} - -// Returns the mean of an array -function mean(array) { - return array.reduce((sum, val) => sum + val, 0) / array.length; -} - -// Returns the sample standard deviation of an array -function standardDeviation(array) { - const arrMean = mean(array); - const total = array.reduce((sum, val) => sum + Math.pow(val - arrMean, 2), 0); - return Math.sqrt(total / (array.length - 1)); -} - -// Returns the common standard deviation of two arrays -function combinedStandardDeviation(array1, array2) { - const sum1 = Math.pow(standardDeviation(array1), 2) * (array1.length - 1); - const sum2 = Math.pow(standardDeviation(array2), 2) * (array2.length - 1); - return Math.sqrt((sum1 + sum2) / (array1.length + array2.length - 2)); -} - -// Filter large outliers from an array. A 'large outlier' is a value that is at -// least 50 times larger than the mean. This prevents the tests from failing -// due to the standard deviation increase when a function unexpectedly takes -// a very long time to execute. -function filterOutliers(array) { - const arrMean = mean(array); - return array.filter((value) => value / arrMean < 50); -} - -// t_(0.99995, ∞) -// i.e. If a given comparison function is indeed timing-safe, the t-test result -// has a 99.99% chance to be below this threshold. Unfortunately, this means -// that this test will be a bit flakey and will fail 0.01% of the time even if -// crypto.timingSafeEqual is working properly. -// t-table ref: http://www.sjsu.edu/faculty/gerstman/StatPrimer/t-table.pdf -// Note that in reality there are roughly `2 * numTrials - 2` degrees of -// freedom, not ∞. However, assuming `numTrials` is large, this doesn't -// significantly affect the threshold. -const T_THRESHOLD = 3.892; - -const t = getTValue(crypto.timingSafeEqual); -assert( - Math.abs(t) < T_THRESHOLD, - `timingSafeEqual should not leak information from its execution time (t=${t})`, -); - -// As a coherence check to make sure the statistical tests are working, run the -// same benchmarks again, this time with an unsafe comparison function. In this -// case the t-value should be above the threshold. -const unsafeCompare = (bufA, bufB) => bufA.equals(bufB); -const t2 = getTValue(unsafeCompare); -assert( - Math.abs(t2) > T_THRESHOLD, - `Buffer#equals should leak information from its execution time (t=${t2})`, -); From 9587ae9b5b2a61565777f21a26f78e41471ff882 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 2 May 2024 11:37:04 +0200 Subject: [PATCH 05/96] doc: simplify copy-pasting of `branch-diff` commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/52757 Reviewed-By: Michaël Zasso Reviewed-By: Richard Lau Reviewed-By: Mohammed Keyvanzadeh Reviewed-By: Luigi Pinca --- doc/contributing/releases.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/contributing/releases.md b/doc/contributing/releases.md index 2e4a1d2c1faf93..e07c529fcbb962 100644 --- a/doc/contributing/releases.md +++ b/doc/contributing/releases.md @@ -185,7 +185,7 @@ duplicate or not. For a list of commits that could be landed in a minor release on v1.x: ```bash -branch-diff v1.x-staging main --exclude-label=semver-major,dont-land-on-v1.x,backport-requested-v1.x,backport-blocked-v1.x,backport-open-v1.x,backported-to-v1.x --filter-release --format=simple +N=1 sh -c 'branch-diff v$N.x-staging upstream/main --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x --filter-release --format=simple' ``` Previously released commits and version bumps do not need to be @@ -204,7 +204,7 @@ When you are ready to cherry-pick commits, you can automate with the following command. ```bash -branch-diff v1.x-staging main --exclude-label=semver-major,dont-land-on-v1.x,backport-requested-v1.x,backport-blocked-v1.x,backport-open-v1.x,backported-to-v1.x --filter-release --format=sha --reverse | xargs git cherry-pick +N=1 sh -c 'branch-diff v$N.x-staging upstream/main --exclude-label=semver-major,dont-land-on-v$N.x,backport-requested-v$N.x,backport-blocked-v$N.x,backport-open-v$N.x,backported-to-v$N.x --filter-release --format=sha --reverse' | xargs git cherry-pick -S ``` For patch releases, make sure to add the `semver-minor` tag From 5161d95c30074191938cbaa51d32fe7951b1b546 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 2 May 2024 14:54:46 +0200 Subject: [PATCH 06/96] zlib: expose zlib.crc32() This patch exposes the crc32() function from zlib to user-land. It computes a 32-bit Cyclic Redundancy Check checksum of `data`. If `value` is specified, it is used as the starting value of the checksum, otherwise, 0 is used as the starting value. ```js const zlib = require('node:zlib'); const { Buffer } = require('node:buffer'); let crc = zlib.crc32('hello'); // 907060870 crc = zlib.crc32('world', crc); // 4192936109 crc = zlib.crc32(Buffer.from('hello')); // 907060870 crc = zlib.crc32(Buffer.from('world'), crc); // 4192936109 ``` PR-URL: https://github.com/nodejs/node/pull/52692 Reviewed-By: Yagiz Nizipli Reviewed-By: Luigi Pinca Reviewed-By: Anna Henningsen Reviewed-By: Mohammed Keyvanzadeh Reviewed-By: Benjamin Gruenbaum Reviewed-By: James M Snell --- doc/api/zlib.md | 62 +++++++++ lib/zlib.js | 11 ++ src/node_zlib.cc | 29 +++++ test/parallel/test-zlib-crc32.js | 211 +++++++++++++++++++++++++++++++ 4 files changed, 313 insertions(+) create mode 100644 test/parallel/test-zlib-crc32.js diff --git a/doc/api/zlib.md b/doc/api/zlib.md index d5daa16a007f9f..9e94a076f5478c 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -712,6 +712,67 @@ The `zlib.bytesWritten` property specifies the number of bytes written to the engine, before the bytes are processed (compressed or decompressed, as appropriate for the derived class). +### `zlib.crc32(data[, value])` + + + +* `data` {string|Buffer|TypedArray|DataView} When `data` is a string, + it will be encoded as UTF-8 before being used for computation. +* `value` {integer} An optional starting value. It must be a 32-bit unsigned + integer. **Default:** `0` +* Returns: {integer} A 32-bit unsigned integer containing the checksum. + +Computes a 32-bit [Cyclic Redundancy Check][] checksum of `data`. If +`value` is specified, it is used as the starting value of the checksum, +otherwise, 0 is used as the starting value. + +The CRC algorithm is designed to compute checksums and to detect error +in data transmission. It's not suitable for cryptographic authentication. + +To be consistent with other APIs, if the `data` is a string, it will +be encoded with UTF-8 before being used for computation. If users only +use Node.js to compute and match the checksums, this works well with +other APIs that uses the UTF-8 encoding by default. + +Some third-party JavaScript libraries compute the checksum on a +string based on `str.charCodeAt()` so that it can be run in browsers. +If users want to match the checksum computed with this kind of library +in the browser, it's better to use the same library in Node.js +if it also runs in Node.js. If users have to use `zlib.crc32()` to +match the checksum produced by such a third-party library: + +1. If the library accepts `Uint8Array` as input, use `TextEncoder` + in the browser to encode the string into a `Uint8Array` with UTF-8 + encoding, and compute the checksum based on the UTF-8 encoded string + in the browser. +2. If the library only takes a string and compute the data based on + `str.charCodeAt()`, on the Node.js side, convert the string into + a buffer using `Buffer.from(str, 'utf16le')`. + +```mjs +import zlib from 'node:zlib'; +import { Buffer } from 'node:buffer'; + +let crc = zlib.crc32('hello'); // 907060870 +crc = zlib.crc32('world', crc); // 4192936109 + +crc = zlib.crc32(Buffer.from('hello', 'utf16le')); // 1427272415 +crc = zlib.crc32(Buffer.from('world', 'utf16le'), crc); // 4150509955 +``` + +```cjs +const zlib = require('node:zlib'); +const { Buffer } = require('node:buffer'); + +let crc = zlib.crc32('hello'); // 907060870 +crc = zlib.crc32('world', crc); // 4192936109 + +crc = zlib.crc32(Buffer.from('hello', 'utf16le')); // 1427272415 +crc = zlib.crc32(Buffer.from('world', 'utf16le'), crc); // 4150509955 +``` + ### `zlib.close([callback])` -Closes all connections connected to this server. +Closes all connections connected to this server, including active connections +connected to this server which are sending a request or waiting for a response. + +> This is a forceful way of closing all connections and should be used with +> caution. Whenever using this in conjunction with `server.close`, calling this +> _after_ `server.close` is recommended as to avoid race conditions where new +> connections are created between a call to this and a call to `server.close`. + +```js +const http = require('node:http'); + +const server = http.createServer({ keepAliveTimeout: 60000 }, (req, res) => { + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ + data: 'Hello World!', + })); +}); + +server.listen(8000); +// Close the server after 10 seconds +setTimeout(() => { + server.close(() => { + console.log('server on port 8000 closed successfully'); + }); + // Closes all connections, ensuring the server closes successfully + server.closeAllConnections(); +}, 10000); +``` ### `server.closeIdleConnections()` @@ -1696,6 +1742,37 @@ added: v18.2.0 Closes all connections connected to this server which are not sending a request or waiting for a response. +> Starting with Node.js 19.0.0, there's no need for calling this method in +> conjunction with `server.close` to reap `keep-alive` connections. Using it +> won't cause any harm though, and it can be useful to ensure backwards +> compatibility for libraries and applications that need to support versions +> older than 19.0.0. Whenever using this in conjunction with `server.close`, +> calling this _after_ `server.close` is recommended as to avoid race +> conditions where new connections are created between a call to this and a +> call to `server.close`. + +```js +const http = require('node:http'); + +const server = http.createServer({ keepAliveTimeout: 60000 }, (req, res) => { + res.writeHead(200, { 'Content-Type': 'application/json' }); + res.end(JSON.stringify({ + data: 'Hello World!', + })); +}); + +server.listen(8000); +// Close the server after 10 seconds +setTimeout(() => { + server.close(() => { + console.log('server on port 8000 closed successfully'); + }); + // Closes idle connections, such as keep-alive connections. Server will close + // once remaining active connections are terminated + server.closeIdleConnections(); +}, 10000); +``` + ### `server.headersTimeout` @@ -1226,6 +1227,8 @@ added: v7.6.0 Activate inspector on `host:port` and break at start of user script. Default `host:port` is `127.0.0.1:9229`. +See [V8 Inspector integration for Node.js][] for further explanation on Node.js debugger. + ### `--inspect-port=[host:]port` + +Activate inspector on `host:port` and wait for debugger to be attached. +Default `host:port` is `127.0.0.1:9229`. + +See [V8 Inspector integration for Node.js][] for further explanation on Node.js debugger. + ### `-i`, `--interactive` * `streams` {Stream\[]|Iterable\[]|AsyncIterable\[]|Function\[]} @@ -76,9 +85,11 @@ added: v15.0.0 * `destination` {Stream|Function} * `source` {AsyncIterable} * Returns: {Promise|AsyncIterable} -* `options` {Object} +* `options` {Object} Pipeline options * `signal` {AbortSignal} - * `end` {boolean} + * `end` {boolean} End the destination stream when the source stream ends. + Transform streams are always ended, even if this value is `false`. + **Default:** `true`. * Returns: {Promise} Fulfills when the pipeline is complete. ```cjs From 95128399f8b15aa70680f45ede5fd2830d423de3 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Sun, 12 May 2024 12:26:55 +0200 Subject: [PATCH 68/96] src: allow preventing debug signal handler start PR-URL: https://github.com/nodejs/node/pull/46681 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- src/env-inl.h | 4 ++++ src/env.h | 1 + src/inspector_agent.cc | 7 +++++-- src/node.h | 6 +++++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/env-inl.h b/src/env-inl.h index 099e7352e68af6..63ce35ba68b48a 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -677,6 +677,10 @@ inline bool Environment::no_global_search_paths() const { !options_->global_search_paths; } +inline bool Environment::should_start_debug_signal_handler() const { + return (flags_ & EnvironmentFlags::kNoStartDebugSignalHandler) == 0; +} + inline bool Environment::no_browser_globals() const { // configure --no-browser-globals #ifdef NODE_NO_BROWSER_GLOBALS diff --git a/src/env.h b/src/env.h index 904dda4caf9695..3b3724d6c7156b 100644 --- a/src/env.h +++ b/src/env.h @@ -801,6 +801,7 @@ class Environment : public MemoryRetainer { inline bool tracks_unmanaged_fds() const; inline bool hide_console_windows() const; inline bool no_global_search_paths() const; + inline bool should_start_debug_signal_handler() const; inline bool no_browser_globals() const; inline uint64_t thread_id() const; inline worker::Worker* worker_context() const; diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index cb82f5239a5638..0e7b8fd1c2b3e5 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -717,8 +717,11 @@ bool Agent::Start(const std::string& path, StartIoThreadAsyncCallback)); uv_unref(reinterpret_cast(&start_io_thread_async)); start_io_thread_async.data = this; - // Ignore failure, SIGUSR1 won't work, but that should not block node start. - StartDebugSignalHandler(); + if (parent_env_->should_start_debug_signal_handler()) { + // Ignore failure, SIGUSR1 won't work, but that should not block node + // start. + StartDebugSignalHandler(); + } parent_env_->AddCleanupHook([](void* data) { Environment* env = static_cast(data); diff --git a/src/node.h b/src/node.h index 58c021f67e92c3..7047a667f7f1b2 100644 --- a/src/node.h +++ b/src/node.h @@ -657,7 +657,11 @@ enum Flags : uint64_t { // This control is needed by embedders who may not want to initialize the V8 // inspector in situations where one has already been created, // e.g. Blink's in Chromium. - kNoCreateInspector = 1 << 9 + kNoCreateInspector = 1 << 9, + // Controls where or not the InspectorAgent for this Environment should + // call StartDebugSignalHandler. This control is needed by embedders who may + // not want to allow other processes to start the V8 inspector. + kNoStartDebugSignalHandler = 1 << 10 }; } // namespace EnvironmentFlags From 800b6f65cfbd343dffb9e87f1a69d00e64a173f2 Mon Sep 17 00:00:00 2001 From: Dario <61739181+DevPres@users.noreply.github.com> Date: Sun, 12 May 2024 12:28:20 +0200 Subject: [PATCH 69/96] test: replace `forEach()` in `test-stream-pipe-unpipe-stream` PR-URL: https://github.com/nodejs/node/pull/50786 Reviewed-By: James M Snell Reviewed-By: Rafael Gonzaga Reviewed-By: Luigi Pinca --- test/parallel/test-stream-pipe-unpipe-streams.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/parallel/test-stream-pipe-unpipe-streams.js b/test/parallel/test-stream-pipe-unpipe-streams.js index b1a673d9450ce8..74c435399335d2 100644 --- a/test/parallel/test-stream-pipe-unpipe-streams.js +++ b/test/parallel/test-stream-pipe-unpipe-streams.js @@ -45,13 +45,12 @@ assert.strictEqual(source._readableState.pipes.length, 0); const checkSrcCleanup = common.mustCall(() => { assert.strictEqual(source._readableState.pipes.length, 0); assert.strictEqual(source._readableState.flowing, false); - - srcCheckEventNames.forEach((eventName) => { + for (const eventName of srcCheckEventNames) { assert.strictEqual( source.listenerCount(eventName), 0, `source's '${eventName}' event listeners not removed` ); - }); + } }); function checkDestCleanup(dest) { @@ -65,13 +64,13 @@ assert.strictEqual(source._readableState.pipes.length, 0); 'listener which is `unpipeChecker`' ); dest.removeListener('unpipe', unpipeChecker); - destCheckEventNames.forEach((eventName) => { + for (const eventName of destCheckEventNames) { assert.strictEqual( dest.listenerCount(eventName), 0, `destination{${currentDestId}}'s '${eventName}' event ` + 'listeners not removed' ); - }); + } if (--destCount === 0) checkSrcCleanup(); From 7603a51d458fecb25edcbda0ad275c2f1d6d562c Mon Sep 17 00:00:00 2001 From: Chenyu Yang Date: Mon, 18 Mar 2024 14:54:58 +0800 Subject: [PATCH 70/96] util: fix `%s` format behavior with `Symbol.toPrimitive` This commit ensures `console.log("%s", obj)` correctly invokes `obj[Symbol.toPrimitive]` for string conversion, fixing unexpected object display issue. PR-URL: https://github.com/nodejs/node/pull/50992 Fixes: https://github.com/nodejs/node/issues/50909 Reviewed-By: Ruben Bridgewater Reviewed-By: Chengzhong Wu Reviewed-By: James M Snell Reviewed-By: Zeyu "Alex" Yang --- lib/internal/util/inspect.js | 6 ++++++ test/parallel/test-util-format.js | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 73da4446f824fe..01c1548ea398b5 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -87,6 +87,7 @@ const { SymbolPrototypeToString, SymbolPrototypeValueOf, SymbolIterator, + SymbolToPrimitive, SymbolToStringTag, TypedArrayPrototypeGetLength, TypedArrayPrototypeGetSymbolToStringTag, @@ -2103,6 +2104,11 @@ function hasBuiltInToString(value) { value = proxyTarget; } + // Check if value has a custom Symbol.toPrimitive transformation. + if (typeof value[SymbolToPrimitive] === 'function') { + return false; + } + // Count objects that have no `toString` function as built-in. if (typeof value.toString !== 'function') { return true; diff --git a/test/parallel/test-util-format.js b/test/parallel/test-util-format.js index 12e7833bb24457..8d2cab5a9c7a1c 100644 --- a/test/parallel/test-util-format.js +++ b/test/parallel/test-util-format.js @@ -269,6 +269,27 @@ assert.strictEqual(util.format('%s', -Infinity), '-Infinity'); ); } +// Symbol.toPrimitive handling for string format specifier +{ + const objectWithToPrimitive = { + [Symbol.toPrimitive](hint) { + switch (hint) { + case 'number': + return 42; + case 'string': + return 'string representation'; + case 'default': + default: + return 'default context'; + } + } + }; + + assert.strictEqual(util.format('%s', +objectWithToPrimitive), '42'); + assert.strictEqual(util.format('%s', objectWithToPrimitive), 'string representation'); + assert.strictEqual(util.format('%s', objectWithToPrimitive + ''), 'default context'); +} + // JSON format specifier assert.strictEqual(util.format('%j'), '%j'); assert.strictEqual(util.format('%j', 42), '42'); From be309bd19dcb0b40cc79d364facd363ecfdc69d5 Mon Sep 17 00:00:00 2001 From: Rafael Gonzaga Date: Sun, 12 May 2024 14:20:51 -0300 Subject: [PATCH 71/96] doc: mention push.followTags config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This has happened in v20.13.0 release. Adding this doc to prevent edge cases where the releaser will sign and push but won't be able to promote the release. PR-URL: https://github.com/nodejs/node/pull/52906 Reviewed-By: Ulises Gascón Reviewed-By: Paolo Insogna Reviewed-By: Marco Ippolito Reviewed-By: Antoine du Hamel --- doc/contributing/releases.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/doc/contributing/releases.md b/doc/contributing/releases.md index 0dab193f1aaf08..9fd8d51fa071a0 100644 --- a/doc/contributing/releases.md +++ b/doc/contributing/releases.md @@ -726,7 +726,17 @@ Install `git-secure-tag` npm module: npm install -g git-secure-tag ``` -Create a tag using the following command: +> Ensure to disable `--follow-tags` in your git settings using: `git config push.followTags false` + +If your private key is protected by a passphrase, you might need to run: + +```bash +export GPG_TTY=$(tty) +``` + +before creating the tag. + +To create a tag use the following command: ```bash git secure-tag -sm "YYYY-MM-DD Node.js vx.y.z () Release" From af29120fa7e1aa52e25eb69b921f67cbab704a76 Mon Sep 17 00:00:00 2001 From: Jason Date: Mon, 13 May 2024 01:24:43 +0800 Subject: [PATCH 72/96] stream: use `ByteLengthQueuingStrategy` when not in `objectMode` Fixes: https://github.com/nodejs/node/issues/46347 PR-URL: https://github.com/nodejs/node/pull/48847 Reviewed-By: James M Snell Reviewed-By: Matteo Collina --- lib/internal/webstreams/adapters.js | 7 +-- test/parallel/test-stream-readable-to-web.js | 62 ++++++++++++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) create mode 100644 test/parallel/test-stream-readable-to-web.js diff --git a/lib/internal/webstreams/adapters.js b/lib/internal/webstreams/adapters.js index 878fd0a0d4d76b..8993ced806d1ff 100644 --- a/lib/internal/webstreams/adapters.js +++ b/lib/internal/webstreams/adapters.js @@ -25,6 +25,7 @@ const { const { CountQueuingStrategy, + ByteLengthQueuingStrategy, } = require('internal/webstreams/queuingstrategies'); const { @@ -417,11 +418,7 @@ function newReadableStreamFromStreamReadable(streamReadable, options = kEmptyObj return new CountQueuingStrategy({ highWaterMark }); } - // When not running in objectMode explicitly, we just fall - // back to a minimal strategy that just specifies the highWaterMark - // and no size algorithm. Using a ByteLengthQueuingStrategy here - // is unnecessary. - return { highWaterMark }; + return new ByteLengthQueuingStrategy({ highWaterMark }); }; const strategy = evaluateStrategyOrFallback(options?.strategy); diff --git a/test/parallel/test-stream-readable-to-web.js b/test/parallel/test-stream-readable-to-web.js new file mode 100644 index 00000000000000..753672b509c173 --- /dev/null +++ b/test/parallel/test-stream-readable-to-web.js @@ -0,0 +1,62 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) { common.skip('missing crypto'); } + +const { Readable } = require('stream'); +const process = require('process'); +const { randomBytes } = require('crypto'); +const assert = require('assert'); + +// Based on: https://github.com/nodejs/node/issues/46347#issuecomment-1413886707 +// edit: make it cross-platform as /dev/urandom is not available on Windows +{ + let currentMemoryUsage = process.memoryUsage().arrayBuffers; + + // We initialize a stream, but not start consuming it + const randomNodeStream = new Readable({ + read(size) { + randomBytes(size, (err, buffer) => { + if (err) { + // If an error occurs, emit an 'error' event + this.emit('error', err); + return; + } + + // Push the random bytes to the stream + this.push(buffer); + }); + } + }); + // after 2 seconds, it'll get converted to web stream + let randomWebStream; + + // We check memory usage every second + // since it's a stream, it shouldn't be higher than the chunk size + const reportMemoryUsage = () => { + const { arrayBuffers } = process.memoryUsage(); + currentMemoryUsage = arrayBuffers; + + assert(currentMemoryUsage <= 256 * 1024 * 1024); + }; + setInterval(reportMemoryUsage, 1000); + + // after 1 second we use Readable.toWeb + // memory usage should stay pretty much the same since it's still a stream + setTimeout(() => { + randomWebStream = Readable.toWeb(randomNodeStream); + }, 1000); + + // after 2 seconds we start consuming the stream + // memory usage will grow, but the old chunks should be garbage-collected pretty quickly + setTimeout(async () => { + // eslint-disable-next-line no-unused-vars + for await (const _ of randomWebStream) { + // Do nothing, just let the stream flow + } + }, 2000); + + setTimeout(() => { + // Test considered passed if we don't crash + process.exit(0); + }, 5000); +} From cc74bf789f4aa10300e6625742e36cf1c004da3d Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Sun, 12 May 2024 18:27:34 +0100 Subject: [PATCH 73/96] test: fix broken env fuzzer by initializing process Signed-off-by: Adam Korczynski PR-URL: https://github.com/nodejs/node/pull/51080 Reviewed-By: James M Snell Reviewed-By: Joyee Cheung --- test/fuzzers/fuzz_env.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/fuzzers/fuzz_env.cc b/test/fuzzers/fuzz_env.cc index 92af0bcb30e660..bace3051f8cecd 100644 --- a/test/fuzzers/fuzz_env.cc +++ b/test/fuzzers/fuzz_env.cc @@ -44,6 +44,7 @@ extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { platform.reset( new node::NodePlatform(kV8ThreadPoolSize, tracing_controller)); v8::V8::InitializePlatform(platform.get()); + cppgc::InitializeProcess(platform->GetPageAllocator()); v8::V8::Initialize(); return 0; } From 5fb829b3403fd2bb885d0b72a0fe8d8d7107e306 Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Sun, 12 May 2024 18:28:44 +0100 Subject: [PATCH 74/96] test: add fuzzer for `ClientHelloParser` Signed-off-by: Adam Korczynski PR-URL: https://github.com/nodejs/node/pull/51088 Reviewed-By: James M Snell --- node.gyp | 43 ++++++++++++++++++++++++++ test/fuzzers/fuzz_ClientHelloParser.cc | 16 ++++++++++ 2 files changed, 59 insertions(+) create mode 100644 test/fuzzers/fuzz_ClientHelloParser.cc diff --git a/node.gyp b/node.gyp index 5abbad6c6ff477..57b46db8fafdb9 100644 --- a/node.gyp +++ b/node.gyp @@ -1049,6 +1049,49 @@ }], ], }, # fuzz_env + { # fuzz_ClientHelloParser.cc + 'target_name': 'fuzz_ClientHelloParser', + 'type': 'executable', + 'dependencies': [ + '<(node_lib_target_name)', + 'deps/histogram/histogram.gyp:histogram', + 'deps/uvwasi/uvwasi.gyp:uvwasi', + ], + 'includes': [ + 'node.gypi' + ], + 'include_dirs': [ + 'src', + 'tools/msvs/genfiles', + 'deps/v8/include', + 'deps/cares/include', + 'deps/uv/include', + 'deps/uvwasi/include', + 'test/cctest', + ], + 'defines': [ + 'NODE_ARCH="<(target_arch)"', + 'NODE_PLATFORM="<(OS)"', + 'NODE_WANT_INTERNALS=1', + ], + 'sources': [ + 'src/node_snapshot_stub.cc', + 'test/fuzzers/fuzz_ClientHelloParser.cc', + ], + 'conditions': [ + ['OS=="linux"', { + 'ldflags': [ '-fsanitize=fuzzer' ] + }], + # Ensure that ossfuzz flag has been set and that we are on Linux + [ 'OS!="linux" or ossfuzz!="true"', { + 'type': 'none', + }], + # Avoid excessive LTO + ['enable_lto=="true"', { + 'ldflags': [ '-fno-lto' ], + }], + ], + }, # fuzz_ClientHelloParser.cc { 'target_name': 'cctest', 'type': 'executable', diff --git a/test/fuzzers/fuzz_ClientHelloParser.cc b/test/fuzzers/fuzz_ClientHelloParser.cc new file mode 100644 index 00000000000000..87d7ae5e303e17 --- /dev/null +++ b/test/fuzzers/fuzz_ClientHelloParser.cc @@ -0,0 +1,16 @@ +/* + * A fuzzer focused on node::crypto::ClientHelloParser. + */ + +#include +#include "crypto/crypto_clienthello-inl.h" + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + node::crypto::ClientHelloParser parser; + bool end_cb_called = false; + parser.Start([](void* arg, auto hello) { }, + [](void* arg) { }, + &end_cb_called); + parser.Parse(data, size); + return 0; +} From 7dda156872f23547b51efad1c04cd66ecbb2f449 Mon Sep 17 00:00:00 2001 From: Adam Korczynski Date: Mon, 11 Dec 2023 15:17:28 +0000 Subject: [PATCH 75/96] test: add fuzzer for native/js string conversion Signed-off-by: Adam Korczynski PR-URL: https://github.com/nodejs/node/pull/51120 Reviewed-By: Yagiz Nizipli --- node.gyp | 45 ++++++++++++ test/fuzzers/fuzz_strings.cc | 135 +++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 test/fuzzers/fuzz_strings.cc diff --git a/node.gyp b/node.gyp index 57b46db8fafdb9..67909bdeb89093 100644 --- a/node.gyp +++ b/node.gyp @@ -1092,6 +1092,51 @@ }], ], }, # fuzz_ClientHelloParser.cc + { # fuzz_strings + 'target_name': 'fuzz_strings', + 'type': 'executable', + 'dependencies': [ + '<(node_lib_target_name)', + 'deps/googletest/googletest.gyp:gtest_prod', + 'deps/histogram/histogram.gyp:histogram', + 'deps/uvwasi/uvwasi.gyp:uvwasi', + 'deps/ada/ada.gyp:ada', + ], + 'includes': [ + 'node.gypi' + ], + 'include_dirs': [ + 'src', + 'tools/msvs/genfiles', + 'deps/v8/include', + 'deps/cares/include', + 'deps/uv/include', + 'deps/uvwasi/include', + 'test/cctest', + ], + 'defines': [ + 'NODE_ARCH="<(target_arch)"', + 'NODE_PLATFORM="<(OS)"', + 'NODE_WANT_INTERNALS=1', + ], + 'sources': [ + 'src/node_snapshot_stub.cc', + 'test/fuzzers/fuzz_strings.cc', + ], + 'conditions': [ + ['OS=="linux"', { + 'ldflags': [ '-fsanitize=fuzzer' ] + }], + # Ensure that ossfuzz flag has been set and that we are on Linux + [ 'OS!="linux" or ossfuzz!="true"', { + 'type': 'none', + }], + # Avoid excessive LTO + ['enable_lto=="true"', { + 'ldflags': [ '-fno-lto' ], + }], + ], + }, # fuzz_strings { 'target_name': 'cctest', 'type': 'executable', diff --git a/test/fuzzers/fuzz_strings.cc b/test/fuzzers/fuzz_strings.cc new file mode 100644 index 00000000000000..8f5e1a473e3148 --- /dev/null +++ b/test/fuzzers/fuzz_strings.cc @@ -0,0 +1,135 @@ +/* + * A fuzzer focused on C string -> Javascript String. +*/ + +#include +#include "js_native_api.h" +#include "js_native_api_v8.h" +#include "node.h" +#include "node_platform.h" +#include "node_internals.h" +#include "node_api_internals.h" +#include "node_url.h" +#include "env-inl.h" +#include "util-inl.h" +#include "v8.h" +#include "libplatform/libplatform.h" +#include "aliased_buffer.h" +#include "fuzz_helper.h" + +using node::AliasedBufferBase; + +/* General set up */ +using ArrayBufferUniquePtr = std::unique_ptr; +using TracingAgentUniquePtr = std::unique_ptr; +using NodePlatformUniquePtr = std::unique_ptr; + +static TracingAgentUniquePtr tracing_agent; +static NodePlatformUniquePtr platform; +static uv_loop_t current_loop; +static napi_env addon_env; + +inline napi_env NewEnv(v8::Local context, + const std::string& module_filename, + int32_t module_api_version) ; + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + uv_os_unsetenv("NODE_OPTIONS"); + std::vector node_argv{ "fuzz_string_conversion" }; + std::vector exec_argv; + std::vector errors; + + node::InitializeNodeWithArgs(&node_argv, &exec_argv, &errors); + + tracing_agent = std::make_unique(); + node::tracing::TraceEventHelper::SetAgent(tracing_agent.get()); + node::tracing::TracingController* tracing_controller = + tracing_agent->GetTracingController(); + CHECK_EQ(0, uv_loop_init(¤t_loop)); + static constexpr int kV8ThreadPoolSize = 4; + platform.reset( + new node::NodePlatform(kV8ThreadPoolSize, tracing_controller)); + v8::V8::InitializePlatform(platform.get()); + cppgc::InitializeProcess(platform->GetPageAllocator()); + v8::V8::Initialize(); + return 0; +} + +class FuzzerFixtureHelper { +public: + v8::Isolate* isolate_; + ArrayBufferUniquePtr allocator; + + FuzzerFixtureHelper() + : allocator(ArrayBufferUniquePtr(node::CreateArrayBufferAllocator(), + &node::FreeArrayBufferAllocator)) { + isolate_ = NewIsolate(allocator.get(), ¤t_loop, platform.get()); + CHECK_NOT_NULL(isolate_); + isolate_->Enter(); + }; + + void Teardown() { + platform->DrainTasks(isolate_); + isolate_->Exit(); + platform->UnregisterIsolate(isolate_); + isolate_->Dispose(); + isolate_ = nullptr; + } +}; + +void EnvTest(v8::Isolate* isolate_, char* env_string, size_t size) { + const v8::HandleScope handle_scope(isolate_); + Argv argv; + + node::EnvironmentFlags::Flags flags = node::EnvironmentFlags::kDefaultFlags; + auto isolate = handle_scope.GetIsolate(); + v8::Local context_ = node::NewContext(isolate); + context_->Enter(); + + node::IsolateData* isolate_data_ = node::CreateIsolateData(isolate, ¤t_loop, + platform.get()); + std::vector args(*argv, *argv + 1); + std::vector exec_args(*argv, *argv + 1); + node::Environment* environment_ = node::CreateEnvironment(isolate_data_, + context_, args, exec_args, flags); + node::Environment* envi = environment_; + SetProcessExitHandler(envi, [&](node::Environment* env_, int exit_code) { + node::Stop(envi); + }); + node::LoadEnvironment(envi, ""); + + + napi_addon_register_func init = [](napi_env env, napi_value exports) { + addon_env = env; + return exports; + }; + v8::Local module_obj = v8::Object::New(isolate); + v8::Local exports_obj = v8::Object::New(isolate); + napi_module_register_by_symbol( + exports_obj, module_obj, context_, init, NAPI_VERSION); + size_t copied1, copied2; + napi_value output1, output2; + char *buf1 = (char *)malloc(size); + char *buf2 = (char *)malloc(size); + napi_create_string_utf8(addon_env, env_string, size, &output1); + napi_get_value_string_utf8(addon_env, output1, buf1, size, &copied1); + napi_create_string_latin1(addon_env, env_string, size, &output2); + napi_get_value_string_latin1(addon_env, output2, buf2, size, &copied2); + free(buf1); + free(buf2); + + // Cleanup! + node::FreeEnvironment(environment_); + node::FreeIsolateData(isolate_data_); + context_->Exit(); +} + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data2, size_t size) { + FuzzerFixtureHelper ffh; + std::string s(reinterpret_cast(data2), size); + EnvTest(ffh.isolate_, (char*)s.c_str(), size); + ffh.Teardown(); + return 0; +} + From 954d2aded48a12a9b1feb5223cd75944c1cd58a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sun, 12 May 2024 19:58:40 +0200 Subject: [PATCH 76/96] cluster: replace `forEach` with `for-of` loop MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jérôme Benoit PR-URL: https://github.com/nodejs/node/pull/50317 Reviewed-By: James M Snell Reviewed-By: Antoine du Hamel --- lib/internal/cluster/child.js | 4 ++-- lib/internal/cluster/primary.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/internal/cluster/child.js b/lib/internal/cluster/child.js index 1bddd3ca0ac103..092e61cdd1f6b0 100644 --- a/lib/internal/cluster/child.js +++ b/lib/internal/cluster/child.js @@ -270,14 +270,14 @@ function _disconnect(primaryInitiated) { } } - handles.forEach((handle) => { + for (const handle of handles.values()) { waitingCount++; if (handle[owner_symbol]) handle[owner_symbol].close(checkWaitingCount); else handle.close(checkWaitingCount); - }); + } handles.clear(); checkWaitingCount(); diff --git a/lib/internal/cluster/primary.js b/lib/internal/cluster/primary.js index 945f440cd19797..107ab258a47e04 100644 --- a/lib/internal/cluster/primary.js +++ b/lib/internal/cluster/primary.js @@ -152,10 +152,10 @@ function removeWorker(worker) { function removeHandlesForWorker(worker) { assert(worker); - handles.forEach((handle, key) => { + for (const { 0: key, 1: handle } of handles) { if (handle.remove(worker)) handles.delete(key); - }); + } } cluster.fork = function(env) { From 033f985e8a848eb6f132c4a0011fe4ff901c9e9f Mon Sep 17 00:00:00 2001 From: theanarkh Date: Mon, 13 May 2024 02:07:46 +0800 Subject: [PATCH 77/96] src: use `S_ISDIR` to check if the file is a directory PR-URL: https://github.com/nodejs/node/pull/52164 Fixes: https://github.com/nodejs/node/issues/52159 Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- src/node_file.cc | 4 ++-- src/permission/fs_permission.cc | 2 +- test/parallel/test-fs-readdir-recursive.js | 14 ++++++++++++++ 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 test/parallel/test-fs-readdir-recursive.js diff --git a/src/node_file.cc b/src/node_file.cc index 0ec5c6f4845e7b..b0aa53420c4efb 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -1151,7 +1151,7 @@ static void InternalModuleStat(const FunctionCallbackInfo& args) { int rc = uv_fs_stat(env->event_loop(), &req, *path, nullptr); if (rc == 0) { const uv_stat_t* const s = static_cast(req.ptr); - rc = !!(s->st_mode & S_IFDIR); + rc = S_ISDIR(s->st_mode); } uv_fs_req_cleanup(&req); @@ -3079,7 +3079,7 @@ BindingData::FilePathIsFileReturnType BindingData::FilePathIsFile( if (rc == 0) { const uv_stat_t* const s = static_cast(req.ptr); - rc = !!(s->st_mode & S_IFDIR); + rc = S_ISDIR(s->st_mode); } uv_fs_req_cleanup(&req); diff --git a/src/permission/fs_permission.cc b/src/permission/fs_permission.cc index 0c881fa266d23d..745ddd96c089ed 100644 --- a/src/permission/fs_permission.cc +++ b/src/permission/fs_permission.cc @@ -20,7 +20,7 @@ std::string WildcardIfDir(const std::string& res) noexcept { int rc = uv_fs_stat(nullptr, &req, res.c_str(), nullptr); if (rc == 0) { const uv_stat_t* const s = static_cast(req.ptr); - if (s->st_mode & S_IFDIR) { + if ((s->st_mode & S_IFMT) == S_IFDIR) { // add wildcard when directory if (res.back() == node::kPathSeparator) { return res + "*"; diff --git a/test/parallel/test-fs-readdir-recursive.js b/test/parallel/test-fs-readdir-recursive.js new file mode 100644 index 00000000000000..f32e600d2a3660 --- /dev/null +++ b/test/parallel/test-fs-readdir-recursive.js @@ -0,0 +1,14 @@ +'use strict'; +const common = require('../common'); +const fs = require('fs'); +const net = require('net'); + +const tmpdir = require('../common/tmpdir'); +tmpdir.refresh(); + +const server = net.createServer().listen(common.PIPE, common.mustCall(() => { + // The process should not crash + // See https://github.com/nodejs/node/issues/52159 + fs.readdirSync(tmpdir.path, { recursive: true }); + server.close(); +})); From 972eafd9835e46516f50e37486cd8bb2ef81a714 Mon Sep 17 00:00:00 2001 From: sinkhaha <1468709106@qq.com> Date: Mon, 13 May 2024 02:16:09 +0800 Subject: [PATCH 78/96] events: update MaxListenersExceededWarning message log PR-URL: https://github.com/nodejs/node/pull/51921 Reviewed-By: Moshe Atlow Reviewed-By: Benjamin Gruenbaum Reviewed-By: Luigi Pinca --- lib/events.js | 2 +- lib/internal/event_target.js | 2 +- .../test-event-emitter-max-listeners-warning-for-null.js | 2 +- .../test-event-emitter-max-listeners-warning-for-symbol.js | 2 +- test/parallel/test-event-emitter-max-listeners-warning.js | 2 +- test/parallel/test-eventtarget-memoryleakwarning.js | 5 ++++- 6 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/events.js b/lib/events.js index b8290619408390..d0f0173ecae8eb 100644 --- a/lib/events.js +++ b/lib/events.js @@ -592,7 +592,7 @@ function _addListener(target, type, listener, prepend) { // No error code for this since it is a Warning const w = genericNodeError( `Possible EventEmitter memory leak detected. ${existing.length} ${String(type)} listeners ` + - `added to ${inspect(target, { depth: -1 })}. Use emitter.setMaxListeners() to increase limit`, + `added to ${inspect(target, { depth: -1 })}. MaxListeners is ${m}. Use emitter.setMaxListeners() to increase limit`, { name: 'MaxListenersExceededWarning', emitter: target, type: type, count: existing.length }); process.emitWarning(w); } diff --git a/lib/internal/event_target.js b/lib/internal/event_target.js index 94a257062147f8..0ebba99f351808 100644 --- a/lib/internal/event_target.js +++ b/lib/internal/event_target.js @@ -565,7 +565,7 @@ class EventTarget { // eslint-disable-next-line no-restricted-syntax const w = new Error('Possible EventTarget memory leak detected. ' + `${size} ${type} listeners ` + - `added to ${inspect(this, { depth: -1 })}. Use ` + + `added to ${inspect(this, { depth: -1 })}. MaxListeners is ${this[kMaxEventTargetListeners]}. Use ` + 'events.setMaxListeners() to increase limit'); w.name = 'MaxListenersExceededWarning'; w.target = this; diff --git a/test/parallel/test-event-emitter-max-listeners-warning-for-null.js b/test/parallel/test-event-emitter-max-listeners-warning-for-null.js index 40b5f798cbadb0..81cfc96f43a32d 100644 --- a/test/parallel/test-event-emitter-max-listeners-warning-for-null.js +++ b/test/parallel/test-event-emitter-max-listeners-warning-for-null.js @@ -16,7 +16,7 @@ process.on('warning', common.mustCall((warning) => { assert.strictEqual(warning.count, 2); assert.strictEqual(warning.type, null); assert.ok(warning.message.includes( - '2 null listeners added to [EventEmitter].')); + '2 null listeners added to [EventEmitter]. MaxListeners is 1.')); })); e.on(null, () => {}); diff --git a/test/parallel/test-event-emitter-max-listeners-warning-for-symbol.js b/test/parallel/test-event-emitter-max-listeners-warning-for-symbol.js index c27b38c2523453..212f9fb1b27a0a 100644 --- a/test/parallel/test-event-emitter-max-listeners-warning-for-symbol.js +++ b/test/parallel/test-event-emitter-max-listeners-warning-for-symbol.js @@ -18,7 +18,7 @@ process.on('warning', common.mustCall((warning) => { assert.strictEqual(warning.count, 2); assert.strictEqual(warning.type, symbol); assert.ok(warning.message.includes( - '2 Symbol(symbol) listeners added to [EventEmitter].')); + '2 Symbol(symbol) listeners added to [EventEmitter]. MaxListeners is 1.')); })); e.on(symbol, () => {}); diff --git a/test/parallel/test-event-emitter-max-listeners-warning.js b/test/parallel/test-event-emitter-max-listeners-warning.js index 3d047766b38fd9..fc23355349ef79 100644 --- a/test/parallel/test-event-emitter-max-listeners-warning.js +++ b/test/parallel/test-event-emitter-max-listeners-warning.js @@ -23,7 +23,7 @@ process.on('warning', common.mustCall((warning) => { assert.strictEqual(warning.count, 2); assert.strictEqual(warning.type, 'event-type'); assert.ok(warning.message.includes( - '2 event-type listeners added to [FakeInput].')); + '2 event-type listeners added to [FakeInput]. MaxListeners is 1.')); })); e.on('event-type', () => {}); diff --git a/test/parallel/test-eventtarget-memoryleakwarning.js b/test/parallel/test-eventtarget-memoryleakwarning.js index 36fe068fb806d6..b2da553ab4cacb 100644 --- a/test/parallel/test-eventtarget-memoryleakwarning.js +++ b/test/parallel/test-eventtarget-memoryleakwarning.js @@ -12,18 +12,21 @@ const { setTimeout } = require('timers/promises'); common.expectWarning({ MaxListenersExceededWarning: [ ['Possible EventTarget memory leak detected. 3 foo listeners added to ' + - 'EventTarget. Use events.setMaxListeners() ' + + 'EventTarget. MaxListeners is 2. Use events.setMaxListeners() ' + 'to increase limit'], ['Possible EventTarget memory leak detected. 3 foo listeners added to ' + '[MessagePort [EventTarget]]. ' + + 'MaxListeners is 2. ' + 'Use events.setMaxListeners() to increase ' + 'limit'], ['Possible EventTarget memory leak detected. 3 foo listeners added to ' + '[MessagePort [EventTarget]]. ' + + 'MaxListeners is 2. ' + 'Use events.setMaxListeners() to increase ' + 'limit'], ['Possible EventTarget memory leak detected. 3 foo listeners added to ' + '[AbortSignal]. ' + + 'MaxListeners is 2. ' + 'Use events.setMaxListeners() to increase ' + 'limit'], ], From 3a1d17a9b1bd0c60666b7e4b7364fe5cbd086c8e Mon Sep 17 00:00:00 2001 From: Alex Crawford Date: Sun, 12 May 2024 11:54:03 -0700 Subject: [PATCH 79/96] doc: mention quicker way to build docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `make doc-only` skips the process of building Node, which speeds things up considerably for new contributors. PR-URL: https://github.com/nodejs/node/pull/52937 Reviewed-By: Antoine du Hamel Reviewed-By: Rafael Gonzaga Reviewed-By: Richard Lau Reviewed-By: Marco Ippolito Reviewed-By: Ulises Gascón Reviewed-By: James M Snell Reviewed-By: Luigi Pinca --- doc/contributing/api-documentation.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/doc/contributing/api-documentation.md b/doc/contributing/api-documentation.md index af58c6e53a482c..ffe1cef1386765 100644 --- a/doc/contributing/api-documentation.md +++ b/doc/contributing/api-documentation.md @@ -4,9 +4,8 @@ The Node.js API documentation is generated by an in-house tooling that resides within the [tools/doc](https://github.com/nodejs/node/tree/main/tools/doc) directory. -The build process (using `make doc`) uses this tooling to parse the markdown -files in [doc/api](https://github.com/nodejs/node/tree/main/doc/api) and -generate the following: +The build process (using `make doc` or `make doc-only`) uses this tooling to +parse the markdown files in [`doc/api/`][] and generate the following: 1. Human-readable HTML in `out/doc/api/*.html` 2. A JSON representation in `out/doc/api/*.json` @@ -302,3 +301,5 @@ mutate the data and appends it to the final JSON object. For a more in-depth information we recommend to refer to the `json.mjs` file as it contains a lot of comments. + +[`doc/api/`]: https://github.com/nodejs/node/tree/main/doc/api From 1d013259285169cc006dc4d2459a83079fc2b608 Mon Sep 17 00:00:00 2001 From: Austin Wright Date: Sun, 12 May 2024 12:15:30 -0700 Subject: [PATCH 80/96] test: verify request payload is uploaded consistently Node.js seems to change how it is uploaded based on the method, but HTTP doesn't make any distinction. Co-authored-by: Austin Wright Co-authored-by: Lenvin Gonsalves Co-authored-by: Antoine du Hamel PR-URL: https://github.com/nodejs/node/pull/34066 Refs: https://github.com/nodejs/node/issues/27880 Reviewed-By: James M Snell --- ...st-http-clientrequest-end-contentlength.js | 51 ++++++++++++++++++ ...p-clientrequest-end-empty-response-body.js | 52 +++++++++++++++++++ .../test-http-clientrequest-write-chunked.js | 52 +++++++++++++++++++ ...test-http-request-method-delete-payload.js | 30 +++++++++++ 4 files changed, 185 insertions(+) create mode 100644 test/known_issues/test-http-clientrequest-end-contentlength.js create mode 100644 test/known_issues/test-http-clientrequest-end-empty-response-body.js create mode 100644 test/known_issues/test-http-clientrequest-write-chunked.js create mode 100644 test/parallel/test-http-request-method-delete-payload.js diff --git a/test/known_issues/test-http-clientrequest-end-contentlength.js b/test/known_issues/test-http-clientrequest-end-contentlength.js new file mode 100644 index 00000000000000..9d5370ad07a303 --- /dev/null +++ b/test/known_issues/test-http-clientrequest-end-contentlength.js @@ -0,0 +1,51 @@ +'use strict'; + +// Refs: https://github.com/nodejs/node/pull/34066 + +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +// Test that ClientRequest#end with default options +// computes and sends a Content-Length header +const upload = 'PUT / HTTP/1.1\r\n\r\n'; +const response = 'content-length: 19\r\n'; + +// Test that the upload is properly received with the same headers, +// regardless of request method +const methods = [ 'GET', 'HEAD', 'DELETE', 'POST', 'PATCH', 'PUT', 'OPTIONS' ]; + +const server = http.createServer(common.mustCall(function(req, res) { + req.on('data', function(chunk) { + assert.strictEqual(chunk, Buffer.from(upload)); + }); + res.setHeader('Content-Type', 'text/plain'); + let payload = `${req.method}\r\n`; + for (let i = 0; i < req.rawHeaders.length; i += 2) { + // Ignore a couple headers that may vary + if (req.rawHeaders[i].toLowerCase() === 'host') continue; + if (req.rawHeaders[i].toLowerCase() === 'connection') continue; + payload += `${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`; + } + res.end(payload); +}), methods.length); + +server.listen(0, function tryNextRequest() { + const method = methods.pop(); + if (method === undefined) return; + const port = server.address().port; + const req = http.request({ method, port }, function(res) { + const chunks = []; + res.on('data', function(chunk) { + chunks.push(chunk); + }); + res.on('end', function() { + const received = Buffer.concat(chunks).toString(); + const expected = method.toLowerCase() + '\r\n' + response; + assert.strictEqual(received.toLowerCase(), expected); + tryNextRequest(); + }); + }); + + req.end(upload); +}).unref(); diff --git a/test/known_issues/test-http-clientrequest-end-empty-response-body.js b/test/known_issues/test-http-clientrequest-end-empty-response-body.js new file mode 100644 index 00000000000000..2edbe239a3cae2 --- /dev/null +++ b/test/known_issues/test-http-clientrequest-end-empty-response-body.js @@ -0,0 +1,52 @@ +'use strict'; + +// Refs: https://github.com/nodejs/node/pull/34066 + +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +// Test that ClientRequest#end with default options +// and empty payload sends neither Content-Length nor Transfer-Encoding. +// Sending Content-Length: 0 would be acceptable, but is unnecessary. +const upload = 'PUT / HTTP/1.1\r\n\r\n'; +const response = ''; + +// Test that the upload is properly received with the same headers, +// regardless of request method. +const methods = [ 'GET', 'HEAD', 'DELETE', 'POST', 'PATCH', 'PUT', 'OPTIONS' ]; + +const server = http.createServer(common.mustCall(function(req, res) { + req.on('data', function(chunk) { + assert.strictEqual(chunk.toString(), upload); + }); + res.setHeader('Content-Type', 'text/plain'); + res.write(`${req.method}\r\n`); + for (let i = 0; i < req.rawHeaders.length; i += 2) { + // Ignore a couple headers that may vary + if (req.rawHeaders[i].toLowerCase() === 'host') continue; + if (req.rawHeaders[i].toLowerCase() === 'connection') continue; + res.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`); + } + res.end(); +}), methods.length); + +server.listen(0, function tryNextRequest() { + const method = methods.pop(); + if (method === undefined) return; + const port = server.address().port; + const req = http.request({ method, port }, function(res) { + const chunks = []; + res.on('data', function(chunk) { + chunks.push(chunk); + }); + res.on('end', function() { + const received = Buffer.concat(chunks).toString(); + const expected = method.toLowerCase() + '\r\n' + response; + assert.strictEqual(received.toLowerCase(), expected); + tryNextRequest(); + }); + }); + + req.end(); +}).unref(); diff --git a/test/known_issues/test-http-clientrequest-write-chunked.js b/test/known_issues/test-http-clientrequest-write-chunked.js new file mode 100644 index 00000000000000..2cf63a8be85297 --- /dev/null +++ b/test/known_issues/test-http-clientrequest-write-chunked.js @@ -0,0 +1,52 @@ +'use strict'; + +// Refs: https://github.com/nodejs/node/pull/34066 + +const common = require('../common'); +const assert = require('assert'); +const http = require('http'); + +// Test that ClientRequest#write with default options +// uses a chunked Transfer-Encoding +const upload = 'PUT / HTTP/1.1\r\n\r\n'; +const response = 'transfer-encoding: chunked\r\n'; + +// Test that the upload is properly received with the same headers, +// regardless of request method. +const methods = [ 'GET', 'HEAD', 'DELETE', 'POST', 'PATCH', 'PUT', 'OPTIONS' ]; + +const server = http.createServer(common.mustCall(function(req, res) { + req.on('data', function(chunk) { + assert.strictEqual(chunk.toString(), upload); + }); + res.setHeader('Content-Type', 'text/plain'); + res.write(`${req.method}\r\n`); + for (let i = 0; i < req.rawHeaders.length; i += 2) { + // Ignore a couple headers that may vary + if (req.rawHeaders[i].toLowerCase() === 'host') continue; + if (req.rawHeaders[i].toLowerCase() === 'connection') continue; + res.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`); + } + res.end(); +}), methods.length); + +server.listen(0, function tryNextRequest() { + const method = methods.pop(); + if (method === undefined) return; + const port = server.address().port; + const req = http.request({ method, port }, function(res) { + const chunks = []; + res.on('data', function(chunk) { + chunks.push(chunk); + }); + res.on('end', function() { + const received = Buffer.concat(chunks).toString(); + const expected = method.toLowerCase() + '\r\n' + response; + assert.strictEqual(received.toLowerCase(), expected); + tryNextRequest(); + }); + }); + + req.write(upload); + req.end(); +}).unref(); diff --git a/test/parallel/test-http-request-method-delete-payload.js b/test/parallel/test-http-request-method-delete-payload.js new file mode 100644 index 00000000000000..03728846df69d6 --- /dev/null +++ b/test/parallel/test-http-request-method-delete-payload.js @@ -0,0 +1,30 @@ +'use strict'; +const common = require('../common'); + +const assert = require('assert'); +const http = require('http'); + +const data = 'PUT / HTTP/1.1\r\n\r\n'; + +const server = http.createServer(common.mustCall(function(req, res) { + req.on('data', function(chunk) { + assert.strictEqual(chunk, Buffer.from(data)); + }); + res.setHeader('Content-Type', 'text/plain'); + for (let i = 0; i < req.rawHeaders.length; i += 2) { + if (req.rawHeaders[i].toLowerCase() === 'host') continue; + if (req.rawHeaders[i].toLowerCase() === 'connection') continue; + res.write(`${req.rawHeaders[i]}: ${req.rawHeaders[i + 1]}\r\n`); + } + res.end(); +})).unref(); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + const req = http.request({ method: 'DELETE', port }, function(res) { + res.resume(); + }); + + req.write(data); + req.end(); +})); From 0fb7c18f10b0a88e762a141e1fb94158ea12d569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20Ate=C5=9F=20UZUN?= Date: Sun, 12 May 2024 22:17:14 +0300 Subject: [PATCH 81/96] crypto: fix duplicated switch-case return values PR-URL: https://github.com/nodejs/node/pull/49030 Reviewed-By: Filip Skokan Reviewed-By: Luigi Pinca --- lib/internal/crypto/util.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js index e429cbc1e744e6..284b23c9ae618b 100644 --- a/lib/internal/crypto/util.js +++ b/lib/internal/crypto/util.js @@ -510,10 +510,14 @@ function getUsagesUnion(usageSet, ...usages) { function getBlockSize(name) { switch (name) { - case 'SHA-1': return 512; - case 'SHA-256': return 512; - case 'SHA-384': return 1024; - case 'SHA-512': return 1024; + case 'SHA-1': + // Fall through + case 'SHA-256': + return 512; + case 'SHA-384': + // Fall through + case 'SHA-512': + return 1024; } } From 0513e07805d4f3e8f46945f1f438fa156e2d8fd1 Mon Sep 17 00:00:00 2001 From: Gibby Free <33621269+gibbyfree@users.noreply.github.com> Date: Sun, 12 May 2024 12:19:54 -0700 Subject: [PATCH 82/96] test: use `for-of` instead of `forEach` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/49790 Reviewed-By: Tobias Nießen Reviewed-By: Luigi Pinca Reviewed-By: Ruy Adorno Reviewed-By: Antoine du Hamel --- test/parallel/test-path-parse-format.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/test/parallel/test-path-parse-format.js b/test/parallel/test-path-parse-format.js index 52acd836cce87b..e834031403034c 100644 --- a/test/parallel/test-path-parse-format.js +++ b/test/parallel/test-path-parse-format.js @@ -148,13 +148,11 @@ const trailingTests = [ ], ]; const failures = []; -trailingTests.forEach((test) => { - const parse = test[0]; +for (const [parse, testList] of trailingTests) { const os = parse === path.win32.parse ? 'win32' : 'posix'; - test[1].forEach((test) => { - const actual = parse(test[0]); - const expected = test[1]; - const message = `path.${os}.parse(${JSON.stringify(test[0])})\n expect=${ + for (const [input, expected] of testList) { + const actual = parse(input); + const message = `path.${os}.parse(${JSON.stringify(input)})\n expect=${ JSON.stringify(expected)}\n actual=${JSON.stringify(actual)}`; const actualKeys = Object.keys(actual); const expectedKeys = Object.keys(expected); @@ -170,8 +168,8 @@ trailingTests.forEach((test) => { } if (failed) failures.push(`\n${message}`); - }); -}); + } +} assert.strictEqual(failures.length, 0, failures.join('')); function checkErrors(path) { From 8b3e83bb53783e5d56af504aeb82305f0865c0da Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Sun, 12 May 2024 15:29:25 -0400 Subject: [PATCH 83/96] buffer: even faster atob PR-URL: https://github.com/nodejs/node/pull/52443 Reviewed-By: Yagiz Nizipli Reviewed-By: Benjamin Gruenbaum --- src/node_buffer.cc | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index e63318b65b2e61..e7e3ead4416a40 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -1286,19 +1286,31 @@ static void Atob(const FunctionCallbackInfo& args) { auto ext = input->GetExternalOneByteStringResource(); size_t expected_length = simdutf::maximal_binary_length_from_base64(ext->data(), ext->length()); - buffer.AllocateSufficientStorage(expected_length + 1); - buffer.SetLengthAndZeroTerminate(expected_length); + buffer.AllocateSufficientStorage(expected_length); + buffer.SetLength(expected_length); result = simdutf::base64_to_binary( ext->data(), ext->length(), buffer.out(), simdutf::base64_default); + } else if (input->IsOneByte()) { + MaybeStackBuffer stack_buf(input->Length()); + input->WriteOneByte(args.GetIsolate(), + stack_buf.out(), + 0, + input->Length(), + String::NO_NULL_TERMINATION); + const char* data = reinterpret_cast(*stack_buf); + size_t expected_length = + simdutf::maximal_binary_length_from_base64(data, input->Length()); + buffer.AllocateSufficientStorage(expected_length); + buffer.SetLength(expected_length); + result = simdutf::base64_to_binary(data, input->Length(), buffer.out()); } else { // 16-bit case String::Value value(env->isolate(), input); auto data = reinterpret_cast(*value); size_t expected_length = simdutf::maximal_binary_length_from_base64(data, value.length()); - buffer.AllocateSufficientStorage(expected_length + 1); - buffer.SetLengthAndZeroTerminate(expected_length); - result = simdutf::base64_to_binary( - data, value.length(), buffer.out(), simdutf::base64_default); + buffer.AllocateSufficientStorage(expected_length); + buffer.SetLength(expected_length); + result = simdutf::base64_to_binary(data, value.length(), buffer.out()); } if (result.error == simdutf::error_code::SUCCESS) { From 227093bfecd318ab99245165cbf58225f426ccbf Mon Sep 17 00:00:00 2001 From: Zhenwei Jin <109658203+kylo5aby@users.noreply.github.com> Date: Mon, 13 May 2024 03:46:13 +0800 Subject: [PATCH 84/96] assert: add deep equal check for more Error type PR-URL: https://github.com/nodejs/node/pull/51805 Fixes: https://github.com/nodejs/node/issues/51793 Reviewed-By: Chengzhong Wu --- doc/api/assert.md | 15 +++++++++++---- lib/internal/util/comparisons.js | 20 +++++++++++++++++--- test/parallel/test-assert-deep.js | 23 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/doc/api/assert.md b/doc/api/assert.md index 92121c42f20a46..ca1fc7ca9772a4 100644 --- a/doc/api/assert.md +++ b/doc/api/assert.md @@ -555,6 +555,9 @@ An alias of [`assert.ok()`][]. + +> Stability: 1 - Experimental + +* `count` {number} The number of assertions and subtests that are expected to run. + +This function is used to set the number of assertions and subtests that are expected to run +within the test. If the number of assertions and subtests that run does not match the +expected count, the test will fail. + +> Note: To make sure assertions are tracked, `t.assert` must be used instead of `assert` directly. + +```js +test('top level test', (t) => { + t.plan(2); + t.assert.ok('some relevant assertion here'); + t.subtest('subtest', () => {}); +}); +``` + +When working with asynchronous code, the `plan` function can be used to ensure that the +correct number of assertions are run: + +```js +test('planning with streams', (t, done) => { + function* generate() { + yield 'a'; + yield 'b'; + yield 'c'; + } + const expected = ['a', 'b', 'c']; + t.plan(expected.length); + const stream = Readable.from(generate()); + stream.on('data', (chunk) => { + t.assert.strictEqual(chunk, expected.shift()); + }); + + stream.on('end', () => { + done(); + }); +}); +``` + ### `context.runOnly(shouldRunOnlyTests)` + +By default, Node.js enables trap-handler-based WebAssembly bound +checks. As a result, V8 does not need to insert inline bound checks +int the code compiled from WebAssembly which may speedup WebAssembly +execution significantly, but this optimization requires allocating +a big virtual memory cage (currently 10GB). If the Node.js process +does not have access to a large enough virtual memory address space +due to system configurations or hardware limitations, users won't +be able to run any WebAssembly that involves allocation in this +virtual memory cage and will see an out-of-memory error. + +```console +$ ulimit -v 5000000 +$ node -p "new WebAssembly.Memory({ initial: 10, maximum: 100 });" +[eval]:1 +new WebAssembly.Memory({ initial: 10, maximum: 100 }); +^ + +RangeError: WebAssembly.Memory(): could not allocate memory + at [eval]:1:1 + at runScriptInThisContext (node:internal/vm:209:10) + at node:internal/process/execution:118:14 + at [eval]-wrapper:6:24 + at runScript (node:internal/process/execution:101:62) + at evalScript (node:internal/process/execution:136:3) + at node:internal/main/eval_string:49:3 + +``` + +`--disable-wasm-trap-handler` disables this optimization so that +users can at least run WebAssembly (with less optimal performance) +when the virtual memory address space available to their Node.js +process is lower than what the V8 WebAssembly memory cage needs. + ### `--disable-proto=mode` By default, Node.js enables trap-handler-based WebAssembly bound @@ -1292,7 +1292,7 @@ endpoint on `http://host:port/json/list`. ### `--inspect-wait[=[host:]port]` Activate inspector on `host:port` and wait for debugger to be attached. diff --git a/doc/api/test.md b/doc/api/test.md index 35741dad2dabc8..87919c01df316e 100644 --- a/doc/api/test.md +++ b/doc/api/test.md @@ -2920,7 +2920,7 @@ The name of the test. > Stability: 1 - Experimental diff --git a/doc/api/zlib.md b/doc/api/zlib.md index 9e94a076f5478c..da839466f1bae9 100644 --- a/doc/api/zlib.md +++ b/doc/api/zlib.md @@ -715,7 +715,7 @@ as appropriate for the derived class). ### `zlib.crc32(data[, value])` * `data` {string|Buffer|TypedArray|DataView} When `data` is a string, diff --git a/doc/changelogs/CHANGELOG_V20.md b/doc/changelogs/CHANGELOG_V20.md index 781446ffe5ebfd..dc1e23049418be 100644 --- a/doc/changelogs/CHANGELOG_V20.md +++ b/doc/changelogs/CHANGELOG_V20.md @@ -9,6 +9,7 @@ +20.15.0
20.14.0
20.13.1
20.13.0
@@ -60,6 +61,196 @@ * [io.js](CHANGELOG_IOJS.md) * [Archive](CHANGELOG_ARCHIVE.md) + + +## 2024-06-20, Version 20.15.0 'Iron' (LTS), @marco-ippolito + +### test\_runner: support test plans + +It is now possible to count the number of assertions and subtests that are expected to run within a test. If the number of assertions and subtests that run does not match the expected count, the test will fail. + +```js +test('top level test', (t) => { + t.plan(2); + t.assert.ok('some relevant assertion here'); + t.subtest('subtest', () => {}); +}); +``` + +Contributed by Colin Ihrig in [#52860](https://github.com/nodejs/node/pull/52860) + +### inspector: introduce the `--inspect-wait` flag + +This release introduces the `--inspect-wait` flag, which allows debugger to wait for attachement. This flag is useful when you want to debug the code from the beginning. Unlike `--inspect-brk`, which breaks on the first line, this flag waits for debugger to be connected and then runs the code as soon as a session is established. + +Contributed by Kohei Ueno in [#52734](https://github.com/nodejs/node/pull/52734) + +### zlib: expose zlib.crc32() + +This release exposes the crc32() function from zlib to user-land. + +It computes a 32-bit Cyclic Redundancy Check checksum of data. If +value is specified, it is used as the starting value of the checksum, +otherwise, 0 is used as the starting value. + +The CRC algorithm is designed to compute checksums and to detect error +in data transmission. It's not suitable for cryptographic authentication. + +```js +const zlib = require('node:zlib'); +const { Buffer } = require('node:buffer'); + +let crc = zlib.crc32('hello'); // 907060870 +crc = zlib.crc32('world', crc); // 4192936109 + +crc = zlib.crc32(Buffer.from('hello', 'utf16le')); // 1427272415 +crc = zlib.crc32(Buffer.from('world', 'utf16le'), crc); // 4150509955 +``` + +Contributed by Joyee Cheung in [#52692](https://github.com/nodejs/node/pull/52692) + +### cli: allow running wasm in limited vmem with --disable-wasm-trap-handler + +By default, Node.js enables trap-handler-based WebAssembly bound +checks. As a result, V8 does not need to insert inline bound checks +int the code compiled from WebAssembly which may speedup WebAssembly +execution significantly, but this optimization requires allocating +a big virtual memory cage (currently 10GB). If the Node.js process +does not have access to a large enough virtual memory address space +due to system configurations or hardware limitations, users won't +be able to run any WebAssembly that involves allocation in this +virtual memory cage and will see an out-of-memory error. + +```console +$ ulimit -v 5000000 +$ node -p "new WebAssembly.Memory({ initial: 10, maximum: 100 });" +[eval]:1 +new WebAssembly.Memory({ initial: 10, maximum: 100 }); +^ + +RangeError: WebAssembly.Memory(): could not allocate memory + at [eval]:1:1 + at runScriptInThisContext (node:internal/vm:209:10) + at node:internal/process/execution:118:14 + at [eval]-wrapper:6:24 + at runScript (node:internal/process/execution:101:62) + at evalScript (node:internal/process/execution:136:3) + at node:internal/main/eval_string:49:3 + +``` + +`--disable-wasm-trap-handler` disables this optimization so that +users can at least run WebAssembly (with a less optimial performance) +when the virtual memory address space available to their Node.js +process is lower than what the V8 WebAssembly memory cage needs. + +Contributed by Joyee Cheung in [#52766](https://github.com/nodejs/node/pull/52766) + +### Other Notable Changes + +* \[[`12512c3d0e`](https://github.com/nodejs/node/commit/12512c3d0e)] - **doc**: add pimterry to collaborators (Tim Perry) [#52874](https://github.com/nodejs/node/pull/52874) +* \[[`9d485b40bb`](https://github.com/nodejs/node/commit/9d485b40bb)] - **(SEMVER-MINOR)** **tools**: fix get\_asan\_state() in tools/test.py (Joyee Cheung) [#52766](https://github.com/nodejs/node/pull/52766) +* \[[`e98c305f52`](https://github.com/nodejs/node/commit/e98c305f52)] - **(SEMVER-MINOR)** **tools**: support max\_virtual\_memory test configuration (Joyee Cheung) [#52766](https://github.com/nodejs/node/pull/52766) +* \[[`dce0300896`](https://github.com/nodejs/node/commit/dce0300896)] - **(SEMVER-MINOR)** **tools**: support != in test status files (Joyee Cheung) [#52766](https://github.com/nodejs/node/pull/52766) + +### Commits + +* \[[`227093bfec`](https://github.com/nodejs/node/commit/227093bfec)] - **assert**: add deep equal check for more Error type (Zhenwei Jin) [#51805](https://github.com/nodejs/node/pull/51805) +* \[[`184cfe5a71`](https://github.com/nodejs/node/commit/184cfe5a71)] - **benchmark**: filter non-present deps from `start-cli-version` (Adam Majer) [#51746](https://github.com/nodejs/node/pull/51746) +* \[[`8b3e83bb53`](https://github.com/nodejs/node/commit/8b3e83bb53)] - **buffer**: even faster atob (Daniel Lemire) [#52443](https://github.com/nodejs/node/pull/52443) +* \[[`8d628c3255`](https://github.com/nodejs/node/commit/8d628c3255)] - **buffer**: use size\_t instead of uint32\_t to avoid segmentation fault (Xavier Stouder) [#48033](https://github.com/nodejs/node/pull/48033) +* \[[`16ae2b2933`](https://github.com/nodejs/node/commit/16ae2b2933)] - **buffer**: remove lines setting indexes to integer value (Zhenwei Jin) [#52588](https://github.com/nodejs/node/pull/52588) +* \[[`48c15d0dcd`](https://github.com/nodejs/node/commit/48c15d0dcd)] - **build**: remove deprecated calls for argument groups (Mohammed Keyvanzadeh) [#52913](https://github.com/nodejs/node/pull/52913) +* \[[`1be8232d17`](https://github.com/nodejs/node/commit/1be8232d17)] - **build**: drop base64 dep in GN build (Cheng) [#52856](https://github.com/nodejs/node/pull/52856) +* \[[`918962d6e7`](https://github.com/nodejs/node/commit/918962d6e7)] - **build**: make simdjson a public dep in GN build (Cheng) [#52755](https://github.com/nodejs/node/pull/52755) +* \[[`5215b6fd8e`](https://github.com/nodejs/node/commit/5215b6fd8e)] - **build, tools**: copy release assets to staging R2 bucket once built (flakey5) [#51394](https://github.com/nodejs/node/pull/51394) +* \[[`473fa73857`](https://github.com/nodejs/node/commit/473fa73857)] - **(SEMVER-MINOR)** **cli**: allow running wasm in limited vmem with --disable-wasm-trap-handler (Joyee Cheung) [#52766](https://github.com/nodejs/node/pull/52766) +* \[[`954d2aded4`](https://github.com/nodejs/node/commit/954d2aded4)] - **cluster**: replace `forEach` with `for-of` loop (Jérôme Benoit) [#50317](https://github.com/nodejs/node/pull/50317) +* \[[`794e450ea7`](https://github.com/nodejs/node/commit/794e450ea7)] - **console**: colorize console error and warn (Jithil P Ponnan) [#51629](https://github.com/nodejs/node/pull/51629) +* \[[`0fb7c18f10`](https://github.com/nodejs/node/commit/0fb7c18f10)] - **crypto**: fix duplicated switch-case return values (Mustafa Ateş UZUN) [#49030](https://github.com/nodejs/node/pull/49030) +* \[[`cd1415c8b2`](https://github.com/nodejs/node/commit/cd1415c8b2)] - _**Revert**_ "**crypto**: make timingSafeEqual faster for Uint8Array" (Tobias Nießen) [#53390](https://github.com/nodejs/node/pull/53390) +* \[[`b774544bb1`](https://github.com/nodejs/node/commit/b774544bb1)] - **deps**: enable unbundling of simdjson, simdutf, ada (Daniel Lemire) [#52924](https://github.com/nodejs/node/pull/52924) +* \[[`da4dbfc5fd`](https://github.com/nodejs/node/commit/da4dbfc5fd)] - **doc**: remove reference to AUTHORS file (Marco Ippolito) [#52960](https://github.com/nodejs/node/pull/52960) +* \[[`2f3f2ff8af`](https://github.com/nodejs/node/commit/2f3f2ff8af)] - **doc**: update hljs with the latest styles (Aviv Keller) [#52911](https://github.com/nodejs/node/pull/52911) +* \[[`3a1d17a9b1`](https://github.com/nodejs/node/commit/3a1d17a9b1)] - **doc**: mention quicker way to build docs (Alex Crawford) [#52937](https://github.com/nodejs/node/pull/52937) +* \[[`be309bd19d`](https://github.com/nodejs/node/commit/be309bd19d)] - **doc**: mention push.followTags config (Rafael Gonzaga) [#52906](https://github.com/nodejs/node/pull/52906) +* \[[`e62c6e2684`](https://github.com/nodejs/node/commit/e62c6e2684)] - **doc**: document pipeline with `end` option (Alois Klink) [#48970](https://github.com/nodejs/node/pull/48970) +* \[[`af27225cf6`](https://github.com/nodejs/node/commit/af27225cf6)] - **doc**: add example for `execFileSync` method and ref to stdio (Evan Shortiss) [#39412](https://github.com/nodejs/node/pull/39412) +* \[[`086626f9b1`](https://github.com/nodejs/node/commit/086626f9b1)] - **doc**: add examples and notes to http server.close et al (mary marchini) [#49091](https://github.com/nodejs/node/pull/49091) +* \[[`3aa3337a00`](https://github.com/nodejs/node/commit/3aa3337a00)] - **doc**: fix `dns.lookup` family `0` and `all` descriptions (Adam Jones) [#51653](https://github.com/nodejs/node/pull/51653) +* \[[`585f2a2e7f`](https://github.com/nodejs/node/commit/585f2a2e7f)] - **doc**: update `fs.realpath` documentation (sinkhaha) [#48170](https://github.com/nodejs/node/pull/48170) +* \[[`4bf3d44e1d`](https://github.com/nodejs/node/commit/4bf3d44e1d)] - **doc**: update fs read documentation for clarity (Mert Can Altin) [#52453](https://github.com/nodejs/node/pull/52453) +* \[[`ae5d47dde3`](https://github.com/nodejs/node/commit/ae5d47dde3)] - **doc**: watermark string behavior (Benjamin Gruenbaum) [#52842](https://github.com/nodejs/node/pull/52842) +* \[[`1e429d10d3`](https://github.com/nodejs/node/commit/1e429d10d3)] - **doc**: exclude commits with baking-for-lts (Marco Ippolito) [#52896](https://github.com/nodejs/node/pull/52896) +* \[[`3df3e37cdb`](https://github.com/nodejs/node/commit/3df3e37cdb)] - **doc**: add names next to release key bash commands (Aviv Keller) [#52878](https://github.com/nodejs/node/pull/52878) +* \[[`12512c3d0e`](https://github.com/nodejs/node/commit/12512c3d0e)] - **doc**: add pimterry to collaborators (Tim Perry) [#52874](https://github.com/nodejs/node/pull/52874) +* \[[`97e0fef019`](https://github.com/nodejs/node/commit/97e0fef019)] - **doc**: add more definitions to GLOSSARY.md (Aviv Keller) [#52798](https://github.com/nodejs/node/pull/52798) +* \[[`91fadac162`](https://github.com/nodejs/node/commit/91fadac162)] - **doc**: make docs more welcoming and descriptive for newcomers (Serkan Özel) [#38056](https://github.com/nodejs/node/pull/38056) +* \[[`a3b20126fd`](https://github.com/nodejs/node/commit/a3b20126fd)] - **doc**: add OpenSSL errors to API docs (John Lamp) [#34213](https://github.com/nodejs/node/pull/34213) +* \[[`9587ae9b5b`](https://github.com/nodejs/node/commit/9587ae9b5b)] - **doc**: simplify copy-pasting of `branch-diff` commands (Antoine du Hamel) [#52757](https://github.com/nodejs/node/pull/52757) +* \[[`6ea72a53c3`](https://github.com/nodejs/node/commit/6ea72a53c3)] - **doc**: add test\_runner to subsystem (Raz Luvaton) [#52774](https://github.com/nodejs/node/pull/52774) +* \[[`972eafd983`](https://github.com/nodejs/node/commit/972eafd983)] - **events**: update MaxListenersExceededWarning message log (sinkhaha) [#51921](https://github.com/nodejs/node/pull/51921) +* \[[`74753ed1fe`](https://github.com/nodejs/node/commit/74753ed1fe)] - **events**: add stop propagation flag to `Event.stopImmediatePropagation` (Mickael Meausoone) [#39463](https://github.com/nodejs/node/pull/39463) +* \[[`75dd009649`](https://github.com/nodejs/node/commit/75dd009649)] - **events**: replace NodeCustomEvent with CustomEvent (Feng Yu) [#43876](https://github.com/nodejs/node/pull/43876) +* \[[`7d38c2e012`](https://github.com/nodejs/node/commit/7d38c2e012)] - **fs**: keep fs.promises.readFile read until EOF is reached (Zhenwei Jin) [#52178](https://github.com/nodejs/node/pull/52178) +* \[[`8cb13120d3`](https://github.com/nodejs/node/commit/8cb13120d3)] - **(SEMVER-MINOR)** **inspector**: introduce the `--inspect-wait` flag (Kohei Ueno) [#52734](https://github.com/nodejs/node/pull/52734) +* \[[`d5ab1de1fd`](https://github.com/nodejs/node/commit/d5ab1de1fd)] - **meta**: move `@anonrig` to TSC regular member (Yagiz Nizipli) [#52932](https://github.com/nodejs/node/pull/52932) +* \[[`f82d086e90`](https://github.com/nodejs/node/commit/f82d086e90)] - **path**: fix toNamespacedPath on Windows (Hüseyin Açacak) [#52915](https://github.com/nodejs/node/pull/52915) +* \[[`121ea13b50`](https://github.com/nodejs/node/commit/121ea13b50)] - **process**: improve event-loop (Aras Abbasi) [#52108](https://github.com/nodejs/node/pull/52108) +* \[[`eceac784aa`](https://github.com/nodejs/node/commit/eceac784aa)] - **repl**: fix disruptive autocomplete without inspector (Nitzan Uziely) [#40661](https://github.com/nodejs/node/pull/40661) +* \[[`89a910be82`](https://github.com/nodejs/node/commit/89a910be82)] - **src**: fix Worker termination in `inspector.waitForDebugger` (Daeyeon Jeong) [#52527](https://github.com/nodejs/node/pull/52527) +* \[[`033f985e8a`](https://github.com/nodejs/node/commit/033f985e8a)] - **src**: use `S_ISDIR` to check if the file is a directory (theanarkh) [#52164](https://github.com/nodejs/node/pull/52164) +* \[[`95128399f8`](https://github.com/nodejs/node/commit/95128399f8)] - **src**: allow preventing debug signal handler start (Shelley Vohr) [#46681](https://github.com/nodejs/node/pull/46681) +* \[[`b162aeae9e`](https://github.com/nodejs/node/commit/b162aeae9e)] - **src**: fix typo Unabled -> Unable (Simon Siefke) [#52820](https://github.com/nodejs/node/pull/52820) +* \[[`2dcbf1894a`](https://github.com/nodejs/node/commit/2dcbf1894a)] - **src**: avoid unused variable 'error' warning (Michaël Zasso) [#52886](https://github.com/nodejs/node/pull/52886) +* \[[`978ee0a635`](https://github.com/nodejs/node/commit/978ee0a635)] - **src**: only apply fix in main thread (Paolo Insogna) [#52702](https://github.com/nodejs/node/pull/52702) +* \[[`8fc52b38c6`](https://github.com/nodejs/node/commit/8fc52b38c6)] - **src**: fix test local edge case (Paolo Insogna) [#52702](https://github.com/nodejs/node/pull/52702) +* \[[`d02907ecc4`](https://github.com/nodejs/node/commit/d02907ecc4)] - **src**: remove misplaced windows code under posix guard in node.cc (Ali Hassan) [#52545](https://github.com/nodejs/node/pull/52545) +* \[[`af29120fa7`](https://github.com/nodejs/node/commit/af29120fa7)] - **stream**: use `ByteLengthQueuingStrategy` when not in `objectMode` (Jason) [#48847](https://github.com/nodejs/node/pull/48847) +* \[[`a5f3dd137c`](https://github.com/nodejs/node/commit/a5f3dd137c)] - **string\_decoder**: throw an error when writing a too long buffer (zhenweijin) [#52215](https://github.com/nodejs/node/pull/52215) +* \[[`65fa95d57d`](https://github.com/nodejs/node/commit/65fa95d57d)] - **test**: add `Debugger.setInstrumentationBreakpoint` known issue (Konstantin Ulitin) [#31137](https://github.com/nodejs/node/pull/31137) +* \[[`0513e07805`](https://github.com/nodejs/node/commit/0513e07805)] - **test**: use `for-of` instead of `forEach` (Gibby Free) [#49790](https://github.com/nodejs/node/pull/49790) +* \[[`1d01325928`](https://github.com/nodejs/node/commit/1d01325928)] - **test**: verify request payload is uploaded consistently (Austin Wright) [#34066](https://github.com/nodejs/node/pull/34066) +* \[[`7dda156872`](https://github.com/nodejs/node/commit/7dda156872)] - **test**: add fuzzer for native/js string conversion (Adam Korczynski) [#51120](https://github.com/nodejs/node/pull/51120) +* \[[`5fb829b340`](https://github.com/nodejs/node/commit/5fb829b340)] - **test**: add fuzzer for `ClientHelloParser` (AdamKorcz) [#51088](https://github.com/nodejs/node/pull/51088) +* \[[`cc74bf789f`](https://github.com/nodejs/node/commit/cc74bf789f)] - **test**: fix broken env fuzzer by initializing process (AdamKorcz) [#51080](https://github.com/nodejs/node/pull/51080) +* \[[`800b6f65cf`](https://github.com/nodejs/node/commit/800b6f65cf)] - **test**: replace `forEach()` in `test-stream-pipe-unpipe-stream` (Dario) [#50786](https://github.com/nodejs/node/pull/50786) +* \[[`d08c9a6a31`](https://github.com/nodejs/node/commit/d08c9a6a31)] - **test**: test pipeline `end` on transform streams (Alois Klink) [#48970](https://github.com/nodejs/node/pull/48970) +* \[[`0be8123ede`](https://github.com/nodejs/node/commit/0be8123ede)] - **test**: improve coverage of lib/readline.js (Rongjian Zhang) [#38646](https://github.com/nodejs/node/pull/38646) +* \[[`410224415c`](https://github.com/nodejs/node/commit/410224415c)] - **test**: updated for each to for of in test file (lyannel) [#50308](https://github.com/nodejs/node/pull/50308) +* \[[`556e9a2127`](https://github.com/nodejs/node/commit/556e9a2127)] - **test**: move `test-http-server-request-timeouts-mixed` to sequential (Madhuri) [#45722](https://github.com/nodejs/node/pull/45722) +* \[[`0638274c07`](https://github.com/nodejs/node/commit/0638274c07)] - **test**: fix DNS cancel tests (Szymon Marczak) [#44432](https://github.com/nodejs/node/pull/44432) +* \[[`311bdc62bd`](https://github.com/nodejs/node/commit/311bdc62bd)] - **test**: add http agent to `executionAsyncResource` (psj-tar-gz) [#34966](https://github.com/nodejs/node/pull/34966) +* \[[`6001b164ab`](https://github.com/nodejs/node/commit/6001b164ab)] - **test**: reduce memory usage of test-worker-stdio (Adam Majer) [#37769](https://github.com/nodejs/node/pull/37769) +* \[[`986bfa26e9`](https://github.com/nodejs/node/commit/986bfa26e9)] - **test**: add common.expectRequiredModule() (Joyee Cheung) [#52868](https://github.com/nodejs/node/pull/52868) +* \[[`2246d4fd1e`](https://github.com/nodejs/node/commit/2246d4fd1e)] - **test**: crypto-rsa-dsa testing for dynamic openssl (Michael Dawson) [#52781](https://github.com/nodejs/node/pull/52781) +* \[[`1dce5dea0b`](https://github.com/nodejs/node/commit/1dce5dea0b)] - **test**: skip some console tests on dumb terminal (Adam Majer) [#37770](https://github.com/nodejs/node/pull/37770) +* \[[`0addeb240c`](https://github.com/nodejs/node/commit/0addeb240c)] - **test**: skip v8-updates/test-linux-perf-logger (Michaël Zasso) [#52821](https://github.com/nodejs/node/pull/52821) +* \[[`56e19e38f3`](https://github.com/nodejs/node/commit/56e19e38f3)] - **test**: drop test-crypto-timing-safe-equal-benchmarks (Rafael Gonzaga) [#52751](https://github.com/nodejs/node/pull/52751) +* \[[`0c5e58958c`](https://github.com/nodejs/node/commit/0c5e58958c)] - **test, crypto**: use correct object on assert (响马) [#51820](https://github.com/nodejs/node/pull/51820) +* \[[`d54aa47ec1`](https://github.com/nodejs/node/commit/d54aa47ec1)] - **(SEMVER-MINOR)** **test\_runner**: support test plans (Colin Ihrig) [#52860](https://github.com/nodejs/node/pull/52860) +* \[[`0289a023a5`](https://github.com/nodejs/node/commit/0289a023a5)] - **test\_runner**: fix watch mode race condition (Moshe Atlow) [#52954](https://github.com/nodejs/node/pull/52954) +* \[[`cf817e192e`](https://github.com/nodejs/node/commit/cf817e192e)] - **test\_runner**: preserve hook promise when executed twice (Moshe Atlow) [#52791](https://github.com/nodejs/node/pull/52791) +* \[[`de541235fe`](https://github.com/nodejs/node/commit/de541235fe)] - **tools**: fix v8-update workflow (Michaël Zasso) [#52957](https://github.com/nodejs/node/pull/52957) +* \[[`f6290bc327`](https://github.com/nodejs/node/commit/f6290bc327)] - **tools**: add --certify-safe to nci-ci (Matteo Collina) [#52940](https://github.com/nodejs/node/pull/52940) +* \[[`0830b3115d`](https://github.com/nodejs/node/commit/0830b3115d)] - **tools**: fix doc update action (Marco Ippolito) [#52890](https://github.com/nodejs/node/pull/52890) +* \[[`9d485b40bb`](https://github.com/nodejs/node/commit/9d485b40bb)] - **(SEMVER-MINOR)** **tools**: fix get\_asan\_state() in tools/test.py (Joyee Cheung) [#52766](https://github.com/nodejs/node/pull/52766) +* \[[`e98c305f52`](https://github.com/nodejs/node/commit/e98c305f52)] - **(SEMVER-MINOR)** **tools**: support max\_virtual\_memory test configuration (Joyee Cheung) [#52766](https://github.com/nodejs/node/pull/52766) +* \[[`dce0300896`](https://github.com/nodejs/node/commit/dce0300896)] - **(SEMVER-MINOR)** **tools**: support != in test status files (Joyee Cheung) [#52766](https://github.com/nodejs/node/pull/52766) +* \[[`57006001ec`](https://github.com/nodejs/node/commit/57006001ec)] - **tools**: prepare custom rules for ESLint v9 (Michaël Zasso) [#52889](https://github.com/nodejs/node/pull/52889) +* \[[`403a4a7557`](https://github.com/nodejs/node/commit/403a4a7557)] - **tools**: update lint-md-dependencies to rollup\@4.17.2 (Node.js GitHub Bot) [#52836](https://github.com/nodejs/node/pull/52836) +* \[[`01eff5860e`](https://github.com/nodejs/node/commit/01eff5860e)] - **tools**: update `gr2m/create-or-update-pull-request-action` (Antoine du Hamel) [#52843](https://github.com/nodejs/node/pull/52843) +* \[[`514f01ed59`](https://github.com/nodejs/node/commit/514f01ed59)] - **tools**: use sccache GitHub action (Michaël Zasso) [#52839](https://github.com/nodejs/node/pull/52839) +* \[[`8f8fb91927`](https://github.com/nodejs/node/commit/8f8fb91927)] - **tools**: specify a commit-message for V8 update workflow (Antoine du Hamel) [#52844](https://github.com/nodejs/node/pull/52844) +* \[[`b83fbf8709`](https://github.com/nodejs/node/commit/b83fbf8709)] - **tools**: fix V8 update workflow (Antoine du Hamel) [#52822](https://github.com/nodejs/node/pull/52822) +* \[[`be9d6f2176`](https://github.com/nodejs/node/commit/be9d6f2176)] - **url,tools,benchmark**: replace deprecated `substr()` (Jungku Lee) [#51546](https://github.com/nodejs/node/pull/51546) +* \[[`7603a51d45`](https://github.com/nodejs/node/commit/7603a51d45)] - **util**: fix `%s` format behavior with `Symbol.toPrimitive` (Chenyu Yang) [#50992](https://github.com/nodejs/node/pull/50992) +* \[[`d7eba50cf3`](https://github.com/nodejs/node/commit/d7eba50cf3)] - **util**: improve `isInsideNodeModules` (uzlopak) [#52147](https://github.com/nodejs/node/pull/52147) +* \[[`4ae4f7e517`](https://github.com/nodejs/node/commit/4ae4f7e517)] - **watch**: allow listening for grouped changes (Matthieu Sieben) [#52722](https://github.com/nodejs/node/pull/52722) +* \[[`1ff8f318c0`](https://github.com/nodejs/node/commit/1ff8f318c0)] - **watch**: enable passthrough ipc in watch mode (Zack) [#50890](https://github.com/nodejs/node/pull/50890) +* \[[`739adf90b1`](https://github.com/nodejs/node/commit/739adf90b1)] - **watch**: fix arguments parsing (Moshe Atlow) [#52760](https://github.com/nodejs/node/pull/52760) +* \[[`5161d95c30`](https://github.com/nodejs/node/commit/5161d95c30)] - **(SEMVER-MINOR)** **zlib**: expose zlib.crc32() (Joyee Cheung) [#52692](https://github.com/nodejs/node/pull/52692) + ## 2024-05-28, Version 20.14.0 'Iron' (LTS), @marco-ippolito diff --git a/src/node_version.h b/src/node_version.h index 5f10a61e726437..79843cb4dac56d 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -23,13 +23,13 @@ #define SRC_NODE_VERSION_H_ #define NODE_MAJOR_VERSION 20 -#define NODE_MINOR_VERSION 14 -#define NODE_PATCH_VERSION 1 +#define NODE_MINOR_VERSION 15 +#define NODE_PATCH_VERSION 0 #define NODE_VERSION_IS_LTS 1 #define NODE_VERSION_LTS_CODENAME "Iron" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n)