From f46649bc5b694901516c1a4dcad28d6bc95adc1a Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 16 Jul 2020 12:28:09 -0400 Subject: [PATCH 01/79] util: print External address from inspect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/nodejs/node/issues/28250 PR-URL: https://github.com/nodejs/node/pull/34398 Backport-PR-URL: https://github.com/nodejs/node/pull/34583 Reviewed-By: Anna Henningsen Reviewed-By: Gus Caplan Reviewed-By: Juan José Arboleda Reviewed-By: James M Snell Reviewed-By: Tobias Nießen --- lib/internal/util/inspect.js | 7 +++++-- src/node_util.cc | 16 ++++++++++++++++ test/parallel/test-util-inspect.js | 4 ++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 495271fa62eecb..e3245010761164 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -63,6 +63,7 @@ const { kRejected, previewEntries, getConstructorName: internalGetConstructorName, + getExternalValue, propertyFilter: { ALL_PROPERTIES, ONLY_ENUMERABLE @@ -977,8 +978,10 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { } } else { if (keys.length === 0 && protoProps === undefined) { - if (isExternal(value)) - return ctx.stylize('[External]', 'special'); + if (isExternal(value)) { + const address = getExternalValue(value).toString(16); + return ctx.stylize(`[External: ${address}]`, 'special'); + } return `${getCtxStyle(value, constructor, tag)}{}`; } braces[0] = `${getCtxStyle(value, constructor, tag)}{`; diff --git a/src/node_util.cc b/src/node_util.cc index 22a372ad09a3bd..f62c2922d5f3e9 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -8,8 +8,10 @@ namespace util { using v8::ALL_PROPERTIES; using v8::Array; using v8::ArrayBufferView; +using v8::BigInt; using v8::Boolean; using v8::Context; +using v8::External; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::Global; @@ -18,6 +20,7 @@ using v8::Integer; using v8::Isolate; using v8::KeyCollectionMode; using v8::Local; +using v8::MaybeLocal; using v8::Object; using v8::ONLY_CONFIGURABLE; using v8::ONLY_ENUMERABLE; @@ -67,6 +70,18 @@ static void GetConstructorName( args.GetReturnValue().Set(name); } +static void GetExternalValue( + const FunctionCallbackInfo& args) { + CHECK(args[0]->IsExternal()); + Isolate* isolate = args.GetIsolate(); + Local external = args[0].As(); + + void* ptr = external->Value(); + uint64_t value = reinterpret_cast(ptr); + Local ret = BigInt::NewFromUnsigned(isolate, value); + args.GetReturnValue().Set(ret); +} + static void GetPromiseDetails(const FunctionCallbackInfo& args) { // Return undefined if it's not a Promise. if (!args[0]->IsPromise()) @@ -296,6 +311,7 @@ void Initialize(Local target, env->SetMethodNoSideEffect(target, "getOwnNonIndexProperties", GetOwnNonIndexProperties); env->SetMethodNoSideEffect(target, "getConstructorName", GetConstructorName); + env->SetMethodNoSideEffect(target, "getExternalValue", GetExternalValue); env->SetMethod(target, "sleep", Sleep); env->SetMethod(target, "arrayBufferViewHasBuffer", ArrayBufferViewHasBuffer); diff --git a/test/parallel/test-util-inspect.js b/test/parallel/test-util-inspect.js index 55dcb851154ecf..ffdf121dd50fb1 100644 --- a/test/parallel/test-util-inspect.js +++ b/test/parallel/test-util-inspect.js @@ -147,8 +147,8 @@ assert.strictEqual( "[String: 'hello'] { [length]: 5, [Symbol(foo)]: 123 }" ); -assert.strictEqual(util.inspect((new JSStream())._externalStream), - '[External]'); +assert.match(util.inspect((new JSStream())._externalStream), + /^\[External: [0-9a-f]+\]$/); { const regexp = /regexp/; From 465968c5f84c77bb168b5677c9af1c21327d31aa Mon Sep 17 00:00:00 2001 From: iandrc Date: Fri, 24 Jul 2020 01:58:35 +0300 Subject: [PATCH 02/79] console: document the behavior of console.assert() Add a description and an example of console.assert() call with no arguments. If called like this, the method should output: "Assertion failed". Fixes: https://github.com/nodejs/node/issues/34500 Refs: https://nodejs.org/dist/latest-v14.x/docs/api/console.html#console_console_assert_value_message Refs: https://console.spec.whatwg.org/#assert PR-URL: https://github.com/nodejs/node/pull/34501 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater Reviewed-By: Anto Aravinth Reviewed-By: Zeyu Yang --- doc/api/console.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/api/console.md b/doc/api/console.md index ffc8825a46cb95..3baac4bdac0da8 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -151,6 +151,7 @@ changes: * `...message` {any} All arguments besides `value` are used as error message. A simple assertion test that verifies whether `value` is truthy. If it is not, +or `value` is not passed, `Assertion failed` is logged. If provided, the error `message` is formatted using [`util.format()`][] by passing along all message arguments. The output is used as the error message. @@ -160,6 +161,8 @@ console.assert(true, 'does nothing'); // OK console.assert(false, 'Whoops %s work', 'didn\'t'); // Assertion failed: Whoops didn't work +console.assert(); +// Assertion failed ``` Calling `console.assert()` with a falsy assertion will only cause the `message` From 692a73588128a007ca57b2e7d62d4e047a776534 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 26 Jul 2020 21:54:58 -0700 Subject: [PATCH 03/79] doc: use sentence-case for headers in SECURITY.md Our doc style guide calls for sentence-case in headers. PR-URL: https://github.com/nodejs/node/pull/34525 Reviewed-By: Ruben Bridgewater Reviewed-By: Stewart X Addison --- SECURITY.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 64714043db7e3b..e121072ffe4381 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,6 +1,6 @@ # Security -## Reporting a Bug in Node.js +## Reporting a bug in Node.js Report security bugs in Node.js via [HackerOne](https://hackerone.com/nodejs). @@ -13,13 +13,13 @@ you informed of the progress being made towards a fix and full announcement, and may ask for additional information or guidance surrounding the reported issue. -### Node.js Bug Bounty Program +### Node.js bug bounty program The Node.js project engages in an official bug bounty program for security researchers and responsible public disclosures. The program is managed through the HackerOne platform. See for further details. -## Reporting a Bug in a third party module +## Reporting a bug in a third party module Security bugs in third party modules should be reported to their respective maintainers and should also be coordinated through the Node.js Ecosystem @@ -31,7 +31,7 @@ Details regarding this process can be found in the Thank you for improving the security of Node.js and its ecosystem. Your efforts and responsible disclosure are greatly appreciated and will be acknowledged. -## Disclosure Policy +## Disclosure policy Here is the security disclosure policy for Node.js @@ -60,14 +60,14 @@ Here is the security disclosure policy for Node.js the release process above to ensure that the disclosure is handled in a consistent manner. -## Receiving Security Updates +## Receiving security updates Security notifications will be distributed via the following methods. * * -## Comments on this Policy +## Comments on this policy If you have suggestions on how this process could be improved please submit a [pull request](https://github.com/nodejs/nodejs.org) or From 70e9eceeee31fb191e14aa17f2f47ce21844b165 Mon Sep 17 00:00:00 2001 From: iandrc Date: Thu, 9 Jul 2020 03:05:04 +0300 Subject: [PATCH 04/79] build: toolchain.gypi and node_gyp.py cleanup Removed `linux_use_gold_flag`, `linux_use_bundled_gold` and `linux_use_bundled_binutils` flags from `tools/v8_gypfiles/toolchain.gypi` and `/tools/gyp_node.py`. Fixes: https://github.com/nodejs/node/issues/34256 PR-URL: https://github.com/nodejs/node/pull/34268 Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell --- tools/gyp_node.py | 12 ------ tools/v8_gypfiles/toolchain.gypi | 63 -------------------------------- 2 files changed, 75 deletions(-) diff --git a/tools/gyp_node.py b/tools/gyp_node.py index 333c89f5ae9f5a..8c7493f3292e83 100755 --- a/tools/gyp_node.py +++ b/tools/gyp_node.py @@ -45,18 +45,6 @@ def run_gyp(args): args.append('-Dcomponent=static_library') args.append('-Dlibrary=static_library') - # Don't compile with -B and -fuse-ld=, we don't bundle ld.gold. Can't be - # set in common.gypi due to how deps/v8/build/toolchain.gypi uses them. - args.append('-Dlinux_use_bundled_binutils=0') - args.append('-Dlinux_use_bundled_gold=0') - args.append('-Dlinux_use_gold_flags=0') - - # Set the current program to this module. This is done because gyp - # will use the program path in targets it generates. If this script was called - # by another script the program name will not be gyp_node.py but whatever - # the name of the script that called it is, leading to incorrect commands - # in generated targets (for example cmd_regen_makefile). - sys.argv[0] = os.path.abspath(__file__) rc = gyp.main(args) if rc != 0: print('Error running GYP') diff --git a/tools/v8_gypfiles/toolchain.gypi b/tools/v8_gypfiles/toolchain.gypi index 196196a4e2d65b..d4bad70d45025e 100644 --- a/tools/v8_gypfiles/toolchain.gypi +++ b/tools/v8_gypfiles/toolchain.gypi @@ -99,34 +99,6 @@ ['OS=="linux" and host_arch=="ia32"', { 'binutils_dir%': 'third_party/binutils/Linux_ia32/Release/bin', }], - - # linux_use_bundled_gold: whether to use the gold linker binary checked - # into third_party/binutils. Force this off via GYP_DEFINES when you - # are using a custom toolchain and need to control -B in ldflags. - # Do not use 32-bit gold on 32-bit hosts as it runs out address space - # for component=static_library builds. - ['((OS=="linux" or OS=="android") and (target_arch=="x64" or target_arch=="arm" or (target_arch=="ia32" and host_arch=="x64"))) or (OS=="linux" and target_arch=="mipsel")', { - 'linux_use_bundled_gold%': 1, - }, { - 'linux_use_bundled_gold%': 0, - }], - # linux_use_bundled_binutils: whether to use the binary binutils - # checked into third_party/binutils. These are not multi-arch so cannot - # be used except on x86 and x86-64 (the only two architectures which - # are currently checke in). Force this off via GYP_DEFINES when you - # are using a custom toolchain and need to control -B in cflags. - ['OS=="linux" and (target_arch=="ia32" or target_arch=="x64")', { - 'linux_use_bundled_binutils%': 1, - }, { - 'linux_use_bundled_binutils%': 0, - }], - # linux_use_gold_flags: whether to use build flags that rely on gold. - # On by default for x64 Linux. - ['OS=="linux" and target_arch=="x64"', { - 'linux_use_gold_flags%': 1, - }, { - 'linux_use_gold_flags%': 0, - }], ], # Indicates if gcmole tools are downloaded by a hook. @@ -990,26 +962,6 @@ '-mx32', ], }], # v8_target_arch=="x32" - ['linux_use_gold_flags==1', { - # Newer gccs and clangs support -fuse-ld, use the flag to force gold - # selection. - # gcc -- http://gcc.gnu.org/onlinedocs/gcc-4.8.0/gcc/Optimize-Options.html - 'ldflags': [ '-fuse-ld=gold', ], - }], - ['linux_use_bundled_binutils==1', { - 'cflags': [ - '-B Date: Mon, 20 Jul 2020 16:05:33 +0300 Subject: [PATCH 05/79] async_hooks: don't reuse resource in HttpAgent when queued MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/34439 Fixes: https://github.com/nodejs/node/issues/34401 Refs: https://github.com/nodejs/node/pull/27581 Reviewed-By: Vladimir de Turckheim Reviewed-By: Gerhard Stöbich --- lib/_http_agent.js | 35 +++++-- .../test-async-local-storage-http-agent.js | 35 +++++++ .../test-http-agent-handle-reuse-parallel.js | 92 +++++++++++++++++++ ...=> test-http-agent-handle-reuse-serial.js} | 2 +- 4 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 test/async-hooks/test-async-local-storage-http-agent.js create mode 100644 test/async-hooks/test-http-agent-handle-reuse-parallel.js rename test/async-hooks/{test-http-agent-handle-reuse.js => test-http-agent-handle-reuse-serial.js} (98%) diff --git a/lib/_http_agent.js b/lib/_http_agent.js index 2d52ea3143b3cd..c4430e86ec3aca 100644 --- a/lib/_http_agent.js +++ b/lib/_http_agent.js @@ -34,6 +34,7 @@ const EventEmitter = require('events'); let debug = require('internal/util/debuglog').debuglog('http', (fn) => { debug = fn; }); +const { AsyncResource } = require('async_hooks'); const { async_id_symbol } = require('internal/async_hooks').symbols; const { codes: { @@ -47,6 +48,7 @@ const { validateNumber } = require('internal/validators'); const kOnKeylog = Symbol('onkeylog'); const kRequestOptions = Symbol('requestOptions'); +const kRequestAsyncResource = Symbol('requestAsyncResource'); // New Agent code. // The largest departure from the previous implementation is that @@ -127,7 +129,17 @@ function Agent(options) { const requests = this.requests[name]; if (requests && requests.length) { const req = requests.shift(); - setRequestSocket(this, req, socket); + const reqAsyncRes = req[kRequestAsyncResource]; + if (reqAsyncRes) { + // Run request within the original async context. + reqAsyncRes.runInAsyncScope(() => { + asyncResetHandle(socket); + setRequestSocket(this, req, socket); + }); + req[kRequestAsyncResource] = null; + } else { + setRequestSocket(this, req, socket); + } if (requests.length === 0) { delete this.requests[name]; } @@ -253,14 +265,7 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */, const sockLen = freeLen + this.sockets[name].length; if (socket) { - // Guard against an uninitialized or user supplied Socket. - const handle = socket._handle; - if (handle && typeof handle.asyncReset === 'function') { - // Assign the handle a new asyncId and run any destroy()/init() hooks. - handle.asyncReset(new ReusedHandle(handle.getProviderType(), handle)); - socket[async_id_symbol] = handle.getAsyncId(); - } - + asyncResetHandle(socket); this.reuseSocket(socket, req); setRequestSocket(this, req, socket); this.sockets[name].push(socket); @@ -284,6 +289,8 @@ Agent.prototype.addRequest = function addRequest(req, options, port/* legacy */, // Used to create sockets for pending requests from different origin req[kRequestOptions] = options; + // Used to capture the original async context. + req[kRequestAsyncResource] = new AsyncResource('QueuedRequest'); this.requests[name].push(req); } @@ -493,6 +500,16 @@ function setRequestSocket(agent, req, socket) { socket.setTimeout(req.timeout); } +function asyncResetHandle(socket) { + // Guard against an uninitialized or user supplied Socket. + const handle = socket._handle; + if (handle && typeof handle.asyncReset === 'function') { + // Assign the handle a new asyncId and run any destroy()/init() hooks. + handle.asyncReset(new ReusedHandle(handle.getProviderType(), handle)); + socket[async_id_symbol] = handle.getAsyncId(); + } +} + module.exports = { Agent, globalAgent: new Agent() diff --git a/test/async-hooks/test-async-local-storage-http-agent.js b/test/async-hooks/test-async-local-storage-http-agent.js new file mode 100644 index 00000000000000..1de535aa709687 --- /dev/null +++ b/test/async-hooks/test-async-local-storage-http-agent.js @@ -0,0 +1,35 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const { AsyncLocalStorage } = require('async_hooks'); +const http = require('http'); + +const asyncLocalStorage = new AsyncLocalStorage(); + +const agent = new http.Agent({ + maxSockets: 1 +}); + +const N = 3; +let responses = 0; + +const server = http.createServer(common.mustCall((req, res) => { + res.end('ok'); +}, N)); + +server.listen(0, common.mustCall(() => { + const port = server.address().port; + + for (let i = 0; i < N; i++) { + asyncLocalStorage.run(i, () => { + http.get({ agent, port }, common.mustCall((res) => { + assert.strictEqual(asyncLocalStorage.getStore(), i); + if (++responses === N) { + server.close(); + agent.destroy(); + } + res.resume(); + })); + }); + } +})); diff --git a/test/async-hooks/test-http-agent-handle-reuse-parallel.js b/test/async-hooks/test-http-agent-handle-reuse-parallel.js new file mode 100644 index 00000000000000..cd73b3ed2cb61c --- /dev/null +++ b/test/async-hooks/test-http-agent-handle-reuse-parallel.js @@ -0,0 +1,92 @@ +'use strict'; +// Flags: --expose-internals +const common = require('../common'); +const initHooks = require('./init-hooks'); +const { checkInvocations } = require('./hook-checks'); +const assert = require('assert'); +const { async_id_symbol } = require('internal/async_hooks').symbols; +const http = require('http'); + +// Checks that the async resource used in init in case of a reused handle +// is not reused. Test is based on parallel\test-async-hooks-http-agent.js. + +const hooks = initHooks(); +hooks.enable(); + +const reqAsyncIds = []; +let socket; +let responses = 0; + +// Make sure a single socket is transparently reused for 2 requests. +const agent = new http.Agent({ + keepAlive: true, + keepAliveMsecs: Infinity, + maxSockets: 1 +}); + +const verifyRequest = (idx) => (res) => { + reqAsyncIds[idx] = res.socket[async_id_symbol]; + assert.ok(reqAsyncIds[idx] > 0, `${reqAsyncIds[idx]} > 0`); + if (socket) { + // Check that both requests share their socket. + assert.strictEqual(res.socket, socket); + } else { + socket = res.socket; + } + + res.on('data', common.mustCallAtLeast(() => {})); + res.on('end', common.mustCall(() => { + if (++responses === 2) { + // Clean up to let the event loop stop. + server.close(); + agent.destroy(); + } + })); +}; + +const server = http.createServer(common.mustCall((req, res) => { + req.once('data', common.mustCallAtLeast(() => { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.write('foo'); + })); + req.on('end', common.mustCall(() => { + res.end('bar'); + })); +}, 2)).listen(0, common.mustCall(() => { + const port = server.address().port; + const payload = 'hello world'; + + // First request. + const r1 = http.request({ + agent, port, method: 'POST' + }, common.mustCall(verifyRequest(0))); + r1.end(payload); + + // Second request. Sent in parallel with the first one. + const r2 = http.request({ + agent, port, method: 'POST' + }, common.mustCall(verifyRequest(1))); + r2.end(payload); +})); + + +process.on('exit', onExit); + +function onExit() { + hooks.disable(); + hooks.sanityCheck(); + const activities = hooks.activities; + + // Verify both invocations + const first = activities.filter((x) => x.uid === reqAsyncIds[0])[0]; + checkInvocations(first, { init: 1, destroy: 1 }, 'when process exits'); + + const second = activities.filter((x) => x.uid === reqAsyncIds[1])[0]; + checkInvocations(second, { init: 1, destroy: 1 }, 'when process exits'); + + // Verify reuse handle has been wrapped + assert.strictEqual(first.type, second.type); + assert.ok(first.handle !== second.handle, 'Resource reused'); + assert.ok(first.handle === second.handle.handle, + 'Resource not wrapped correctly'); +} diff --git a/test/async-hooks/test-http-agent-handle-reuse.js b/test/async-hooks/test-http-agent-handle-reuse-serial.js similarity index 98% rename from test/async-hooks/test-http-agent-handle-reuse.js rename to test/async-hooks/test-http-agent-handle-reuse-serial.js index 4db83bec54a7bf..bbc7183d6e72ca 100644 --- a/test/async-hooks/test-http-agent-handle-reuse.js +++ b/test/async-hooks/test-http-agent-handle-reuse-serial.js @@ -7,7 +7,7 @@ const assert = require('assert'); const { async_id_symbol } = require('internal/async_hooks').symbols; const http = require('http'); -// Checks that the async resource used in init in case of a resused handle +// Checks that the async resource used in init in case of a reused handle // is not reused. Test is based on parallel\test-async-hooks-http-agent.js. const hooks = initHooks(); From 9c442f9786f3c5a50d022b3f11ae6caf17163677 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sun, 26 Jul 2020 22:53:53 -0700 Subject: [PATCH 06/79] test: remove unneeded flag check in test-vm-memleak The `common` module checks that necessary flags are being used, so a check in the test itself is no longer necessary. PR-URL: https://github.com/nodejs/node/pull/34528 Reviewed-By: Ruben Bridgewater Reviewed-By: Luigi Pinca --- test/pummel/test-vm-memleak.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/pummel/test-vm-memleak.js b/test/pummel/test-vm-memleak.js index 94e4055a767096..33f2f3d75905a5 100644 --- a/test/pummel/test-vm-memleak.js +++ b/test/pummel/test-vm-memleak.js @@ -29,11 +29,6 @@ const vm = require('vm'); const start = Date.now(); let maxMem = 0; -const ok = process.execArgv.some(function(arg) { - return arg === '--max_old_space_size=32'; -}); -assert(ok, 'Run this test with --max_old_space_size=32.'); - const interval = setInterval(function() { try { vm.runInNewContext('throw 1;'); From 2703fe498ea210afb9c917460448996b8e301194 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Wed, 29 Jul 2020 10:48:00 -0700 Subject: [PATCH 07/79] n-api: simplify bigint-from-word creation Macro `CHECK_MAYBE_EMPTY_WITH_PREAMBLE()` does the work of checking the `TryCatch` and returning `napi_pending_exception` so this change reuses it for `napi_create_bigint_words()`. Signed-off-by: Gabriel Schulhof PR-URL: https://github.com/nodejs/node/pull/34554 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Michael Dawson --- src/js_native_api_v8.cc | 11 ++++------- test/js-native-api/test_bigint/test.js | 7 +++++++ test/js-native-api/test_bigint/test_bigint.c | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index e99333a6a362d1..37cd1a1ab22109 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -1602,13 +1602,10 @@ napi_status napi_create_bigint_words(napi_env env, v8::MaybeLocal b = v8::BigInt::NewFromWords( context, sign_bit, word_count, words); - if (try_catch.HasCaught()) { - return napi_set_last_error(env, napi_pending_exception); - } else { - CHECK_MAYBE_EMPTY(env, b, napi_generic_failure); - *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked()); - return napi_clear_last_error(env); - } + CHECK_MAYBE_EMPTY_WITH_PREAMBLE(env, b, napi_generic_failure); + + *result = v8impl::JsValueFromV8LocalValue(b.ToLocalChecked()); + return GET_RETURN_STATUS(env); } napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) { diff --git a/test/js-native-api/test_bigint/test.js b/test/js-native-api/test_bigint/test.js index 85a183171743c7..bf9ce5066d6d2a 100644 --- a/test/js-native-api/test_bigint/test.js +++ b/test/js-native-api/test_bigint/test.js @@ -7,6 +7,7 @@ const { TestUint64, TestWords, CreateTooBigBigInt, + MakeBigIntWordsThrow, } = require(`./build/${common.buildType}/test_bigint`); [ @@ -43,3 +44,9 @@ assert.throws(CreateTooBigBigInt, { name: 'Error', message: 'Invalid argument', }); + +// Test that we correctly forward exceptions from the engine. +assert.throws(MakeBigIntWordsThrow, { + name: 'RangeError', + message: 'Maximum BigInt size exceeded' +}); diff --git a/test/js-native-api/test_bigint/test_bigint.c b/test/js-native-api/test_bigint/test_bigint.c index c62a0a6a6c2bbc..181f9103fa3399 100644 --- a/test/js-native-api/test_bigint/test_bigint.c +++ b/test/js-native-api/test_bigint/test_bigint.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -122,6 +123,22 @@ static napi_value CreateTooBigBigInt(napi_env env, napi_callback_info info) { return output; } +// Test that we correctly forward exceptions from the engine. +static napi_value MakeBigIntWordsThrow(napi_env env, napi_callback_info info) { + uint64_t words[10]; + napi_value output; + + napi_status status = napi_create_bigint_words(env, + 0, + INT_MAX, + words, + &output); + if (status != napi_pending_exception) + napi_throw_error(env, NULL, "Expected status `napi_pending_exception`"); + + return NULL; +} + EXTERN_C_START napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { @@ -130,6 +147,7 @@ napi_value Init(napi_env env, napi_value exports) { DECLARE_NAPI_PROPERTY("TestUint64", TestUint64), DECLARE_NAPI_PROPERTY("TestWords", TestWords), DECLARE_NAPI_PROPERTY("CreateTooBigBigInt", CreateTooBigBigInt), + DECLARE_NAPI_PROPERTY("MakeBigIntWordsThrow", MakeBigIntWordsThrow), }; NAPI_CALL(env, napi_define_properties( From 70cf3cbdfa73bbe50add4f88d08388e1047fe216 Mon Sep 17 00:00:00 2001 From: Mary Marchini Date: Sat, 27 Jun 2020 12:38:02 -0700 Subject: [PATCH 08/79] build: auto start Jenkins CI via PR labels Add an Action that will find every PR with the `request-ci` label and will start a Jenkins CI for each of these Pull Requests. The scheduler event is used to circumvent GitHub Actions limitations on Pull Requests from forks (where secrets are not accessible and the GITHUB_TOKEN is read-only). If the Action fails to start a CI, it will add a `request-ci-failed` label and will leave a comment with the error message from NCU. Fixes: https://github.com/nodejs/github-bot/issues/234 PR-URL: https://github.com/nodejs/node/pull/34089 Reviewed-By: Christian Clauss --- .github/workflows/auto-start-ci.yml | 65 +++++++++++++++++++++++++++++ tools/actions/start-ci.sh | 53 +++++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 .github/workflows/auto-start-ci.yml create mode 100755 tools/actions/start-ci.sh diff --git a/.github/workflows/auto-start-ci.yml b/.github/workflows/auto-start-ci.yml new file mode 100644 index 00000000000000..d4c364e2bb2f52 --- /dev/null +++ b/.github/workflows/auto-start-ci.yml @@ -0,0 +1,65 @@ +--- +name: Auto Start CI + +on: + push: + schedule: + # `schedule` event is used instead of `pull_request` because when a + # `pull_requesst` event is triggered on a PR from a fork, GITHUB_TOKEN will + # be read-only, and the Action won't have access to any other repository + # secrets, which it needs to access Jenkins API. Runs every five minutes + # (fastest the scheduler can run). Five minutes is optimistic, it can take + # longer to run. + - cron: "*/5 * * * *" + +jobs: + commitQueue: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + + # Install dependencies + - name: Install jq + run: sudo apt-get install jq -y + - name: Install Node.js + uses: actions/setup-node@v2-beta + with: + node-version: '12' + - name: Install node-core-utils + run: npm install -g node-core-utils + + - name: Set variables + run: | + echo "::set-env name=REPOSITORY::$(echo ${{ github.repository }} | cut -d/ -f2)" + echo "::set-env name=OWNER::${{ github.repository_owner }}" + + # Get Pull Requests + - name: Get Pull Requests + uses: octokit/graphql-action@v2.x + id: get_prs_for_ci + with: + query: | + query prs($owner:String!, $repo:String!) { + repository(owner:$owner, name:$repo) { + pullRequests(labels: ["request-ci"], states: OPEN, last: 100) { + nodes { + number + } + } + } + } + owner: ${{ env.OWNER }} + repo: ${{ env.REPOSITORY }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup node-core-utils + run: | + ncu-config set username ${{ secrets.JENKINS_USER }} + ncu-config set token none + ncu-config set jenkins_token ${{ secrets.JENKINS_TOKEN }} + ncu-config set owner ${{ env.OWNER }} + ncu-config set repo ${{ env.REPOSITORY }} + + - name: Start CI + run: ./tools/start-ci.sh ${{ secrets.GITHUB_TOKEN }} ${{ env.OWNER }} ${{ env.REPOSITORY }} $(echo '${{ steps.get_prs_for_ci.outputs.data }}' | jq '.repository.pullRequests.nodes | map(.number) | .[]') diff --git a/tools/actions/start-ci.sh b/tools/actions/start-ci.sh new file mode 100755 index 00000000000000..528c3544b17fa9 --- /dev/null +++ b/tools/actions/start-ci.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +set -xe + +GITHUB_TOKEN=$1 +OWNER=$2 +REPOSITORY=$3 +API_URL=https://api.github.com +REQUEST_CI_LABEL='request-ci' +REQUEST_CI_FAILED_LABEL='request-ci-failed' +shift 3 + +function issueUrl() { + echo "$API_URL/repos/${OWNER}/${REPOSITORY}/issues/${1}" +} + +function labelsUrl() { + echo "$(issueUrl "${1}")/labels" +} + +function commentsUrl() { + echo "$(issueUrl "${1}")/comments" +} + +for pr in "$@"; do + curl -sL --request DELETE \ + --url "$(labelsUrl "$pr")"/"$REQUEST_CI_LABEL" \ + --header "authorization: Bearer ${GITHUB_TOKEN}" \ + --header 'content-type: application/json' + + ci_started=yes + rm -f output; + ncu-ci run "$pr" >output 2>&1 || ci_started=no + + if [ "$ci_started" == "no" ]; then + # Do we need to reset? + curl -sL --request PUT \ + --url "$(labelsUrl "$pr")" \ + --header "authorization: Bearer ${GITHUB_TOKEN}" \ + --header 'content-type: application/json' \ + --data '{"labels": ["'"${REQUEST_CI_FAILED_LABEL}"'"]}' + + jq -n --arg content "
Couldn't start CI
$(cat output)
" '{body: $content}' > output.json + + curl -sL --request POST \ + --url "$(commentsUrl "$pr")" \ + --header "authorization: Bearer ${GITHUB_TOKEN}" \ + --header 'content-type: application/json' \ + --data @output.json + + rm output.json; + fi +done; From c8104f3d10aecf10d2cbed09a68e90e96dbf9ba3 Mon Sep 17 00:00:00 2001 From: Mary Marchini Date: Fri, 31 Jul 2020 12:58:38 -0700 Subject: [PATCH 09/79] doc: update .mailmap for mmarchini PR-URL: https://github.com/nodejs/node/pull/34586 Reviewed-By: Colin Ihrig Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- .mailmap | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.mailmap b/.mailmap index 4a73a2b352a2e7..64f74f4b08a4b9 100644 --- a/.mailmap +++ b/.mailmap @@ -248,10 +248,11 @@ Marti Martz Martial James Jefferson Martijn Schrage Oblosys Masato Ohba -Matheus Marchini -Matheus Marchini -Matheus Marchini -Matheus Marchini +Mary Marchini +Mary Marchini +Mary Marchini +Mary Marchini +Mary Marchini Matt Lang matt-in-a-hat Matt Reed matthewreed26 Matteo Collina From 7a28c3d543d87de70181d877fcb63a2febd494ec Mon Sep 17 00:00:00 2001 From: Mary Marchini Date: Fri, 31 Jul 2020 13:14:22 -0700 Subject: [PATCH 10/79] doc: update mmarchini contact info PR-URL: https://github.com/nodejs/node/pull/34586 Reviewed-By: Colin Ihrig Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- AUTHORS | 2 +- README.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index e6af564013f31a..839039c541e56d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1983,7 +1983,7 @@ Pierre-Loic Doulcet Fran Herrero Francois KY suman-mitra -Matheus Marchini +Mary Marchini neta Whien Chiahao Lin diff --git a/README.md b/README.md index 84ab9cd5862138..334b6e864bc1be 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ For information about the governance of the Node.js project, see * [mhdawson](https://github.com/mhdawson) - **Michael Dawson** <michael_dawson@ca.ibm.com> (he/him) * [mmarchini](https://github.com/mmarchini) - -**Matheus Marchini** <mat@mmarchini.me> +**Mary Marchini** <oss@mmarchini.me> * [MylesBorins](https://github.com/MylesBorins) - **Myles Borins** <myles.borins@gmail.com> (he/him) * [targos](https://github.com/targos) - @@ -360,7 +360,7 @@ For information about the governance of the Node.js project, see * [misterdjules](https://github.com/misterdjules) - **Julien Gilli** <jgilli@nodejs.org> * [mmarchini](https://github.com/mmarchini) - -**Matheus Marchini** <mat@mmarchini.me> +**Mary Marchini** <oss@mmarchini.me> * [mscdex](https://github.com/mscdex) - **Brian White** <mscdex@mscdex.net> * [MylesBorins](https://github.com/MylesBorins) - From 212d17fa064d899466f1cb890cd42e6342d7d8e4 Mon Sep 17 00:00:00 2001 From: Mary Marchini Date: Fri, 31 Jul 2020 13:43:38 -0700 Subject: [PATCH 11/79] doc: add mmarchini pronouns PR-URL: https://github.com/nodejs/node/pull/34586 Reviewed-By: Colin Ihrig Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 334b6e864bc1be..4e972c8d005d7f 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ For information about the governance of the Node.js project, see * [mhdawson](https://github.com/mhdawson) - **Michael Dawson** <michael_dawson@ca.ibm.com> (he/him) * [mmarchini](https://github.com/mmarchini) - -**Mary Marchini** <oss@mmarchini.me> +**Mary Marchini** <oss@mmarchini.me> (she/her) * [MylesBorins](https://github.com/MylesBorins) - **Myles Borins** <myles.borins@gmail.com> (he/him) * [targos](https://github.com/targos) - @@ -360,7 +360,7 @@ For information about the governance of the Node.js project, see * [misterdjules](https://github.com/misterdjules) - **Julien Gilli** <jgilli@nodejs.org> * [mmarchini](https://github.com/mmarchini) - -**Mary Marchini** <oss@mmarchini.me> +**Mary Marchini** <oss@mmarchini.me> (she/her) * [mscdex](https://github.com/mscdex) - **Brian White** <mscdex@mscdex.net> * [MylesBorins](https://github.com/MylesBorins) - From 8cc9e5eb52dbbff49a594c2c8c07032d0b8f6d98 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Fri, 14 Jun 2019 16:44:18 -0700 Subject: [PATCH 12/79] n-api: support type-tagging objects `napi_instanceof()` is insufficient for reliably establishing the data type to which a pointer stored with `napi_wrap()` or `napi_create_external()` inside a JavaScript object points. Thus, we need a way to "mark" an object with a value that, when later retrieved, can unambiguously tell us whether it is safe to cast the pointer stored inside it to a certain structure. Such a check must survive loading/unloading/multiple instances of an addon, so we use UUIDs chosen *a priori*. Fixes: https://github.com/nodejs/node/issues/28164 Co-authored-by: Anna Henningsen PR-URL: https://github.com/nodejs/node/pull/28237 Reviewed-By: Anna Henningsen Reviewed-By: Michael Dawson Reviewed-By: Colin Ihrig Signed-off-by: Gabriel Schulhof --- benchmark/napi/type-tag-check/binding.gyp | 8 + benchmark/napi/type-tag-check/index.js | 18 ++ benchmark/napi/type-tag/binding.c | 84 ++++++++ benchmark/napi/type-tag/binding.gyp | 8 + benchmark/napi/type-tag/check-object-tag.js | 18 ++ benchmark/napi/type-tag/index.js | 18 ++ doc/api/n-api.md | 213 +++++++++++++++++++ src/env.h | 1 + src/js_native_api.h | 10 + src/js_native_api_types.h | 7 + src/js_native_api_v8.cc | 69 ++++++ src/js_native_api_v8.h | 32 +++ test/js-native-api/test_object/test.js | 18 ++ test/js-native-api/test_object/test_object.c | 41 ++++ 14 files changed, 545 insertions(+) create mode 100644 benchmark/napi/type-tag-check/binding.gyp create mode 100644 benchmark/napi/type-tag-check/index.js create mode 100644 benchmark/napi/type-tag/binding.c create mode 100644 benchmark/napi/type-tag/binding.gyp create mode 100644 benchmark/napi/type-tag/check-object-tag.js create mode 100644 benchmark/napi/type-tag/index.js diff --git a/benchmark/napi/type-tag-check/binding.gyp b/benchmark/napi/type-tag-check/binding.gyp new file mode 100644 index 00000000000000..595ab325233661 --- /dev/null +++ b/benchmark/napi/type-tag-check/binding.gyp @@ -0,0 +1,8 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ '../type-tag/binding.c' ] + } + ] +} diff --git a/benchmark/napi/type-tag-check/index.js b/benchmark/napi/type-tag-check/index.js new file mode 100644 index 00000000000000..346dfb7812dea1 --- /dev/null +++ b/benchmark/napi/type-tag-check/index.js @@ -0,0 +1,18 @@ +'use strict'; +const common = require('../../common.js'); + +let binding; +try { + binding = require(`./build/${common.buildType}/binding`); +} catch { + console.error(`${__filename}: Binding failed to load`); + process.exit(0); +} + +const bench = common.createBenchmark(main, { + n: [1e5, 1e6, 1e7], +}); + +function main({ n }) { + binding.checkObjectTag(n, bench, bench.start, bench.end); +} diff --git a/benchmark/napi/type-tag/binding.c b/benchmark/napi/type-tag/binding.c new file mode 100644 index 00000000000000..7bc8b5d7502e8b --- /dev/null +++ b/benchmark/napi/type-tag/binding.c @@ -0,0 +1,84 @@ +#include +#define NAPI_EXPERIMENTAL +#include + +#define NAPI_CALL(call) \ + do { \ + napi_status status = call; \ + assert(status == napi_ok && #call " failed"); \ + } while (0); + +#define EXPORT_FUNC(env, exports, name, func) \ + do { \ + napi_value js_func; \ + NAPI_CALL(napi_create_function((env), \ + (name), \ + NAPI_AUTO_LENGTH, \ + (func), \ + NULL, \ + &js_func)); \ + NAPI_CALL(napi_set_named_property((env), \ + (exports), \ + (name), \ + js_func)); \ + } while (0); + +static const napi_type_tag tag = { + 0xe7ecbcd5954842f6, 0x9e75161c9bf27282 +}; + +static napi_value TagObject(napi_env env, napi_callback_info info) { + size_t argc = 4; + napi_value argv[4]; + uint32_t n; + uint32_t index; + napi_handle_scope scope; + + NAPI_CALL(napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + NAPI_CALL(napi_get_value_uint32(env, argv[0], &n)); + NAPI_CALL(napi_open_handle_scope(env, &scope)); + napi_value objects[n]; + for (index = 0; index < n; index++) { + NAPI_CALL(napi_create_object(env, &objects[index])); + } + + // Time the object tag creation. + NAPI_CALL(napi_call_function(env, argv[1], argv[2], 0, NULL, NULL)); + for (index = 0; index < n; index++) { + NAPI_CALL(napi_type_tag_object(env, objects[index], &tag)); + } + NAPI_CALL(napi_call_function(env, argv[1], argv[3], 1, &argv[0], NULL)); + + NAPI_CALL(napi_close_handle_scope(env, scope)); + return NULL; +} + +static napi_value CheckObjectTag(napi_env env, napi_callback_info info) { + size_t argc = 4; + napi_value argv[4]; + uint32_t n; + uint32_t index; + bool is_of_type; + + NAPI_CALL(napi_get_cb_info(env, info, &argc, argv, NULL, NULL)); + NAPI_CALL(napi_get_value_uint32(env, argv[0], &n)); + napi_value object; + NAPI_CALL(napi_create_object(env, &object)); + NAPI_CALL(napi_type_tag_object(env, object, &tag)); + + // Time the object tag checking. + NAPI_CALL(napi_call_function(env, argv[1], argv[2], 0, NULL, NULL)); + for (index = 0; index < n; index++) { + NAPI_CALL(napi_check_object_type_tag(env, object, &tag, &is_of_type)); + assert(is_of_type && " type mismatch"); + } + NAPI_CALL(napi_call_function(env, argv[1], argv[3], 1, &argv[0], NULL)); + + return NULL; +} + +NAPI_MODULE_INIT() { + EXPORT_FUNC(env, exports, "tagObject", TagObject); + EXPORT_FUNC(env, exports, "checkObjectTag", CheckObjectTag); + return exports; +} diff --git a/benchmark/napi/type-tag/binding.gyp b/benchmark/napi/type-tag/binding.gyp new file mode 100644 index 00000000000000..413621ade335a1 --- /dev/null +++ b/benchmark/napi/type-tag/binding.gyp @@ -0,0 +1,8 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ 'binding.c' ] + } + ] +} diff --git a/benchmark/napi/type-tag/check-object-tag.js b/benchmark/napi/type-tag/check-object-tag.js new file mode 100644 index 00000000000000..346dfb7812dea1 --- /dev/null +++ b/benchmark/napi/type-tag/check-object-tag.js @@ -0,0 +1,18 @@ +'use strict'; +const common = require('../../common.js'); + +let binding; +try { + binding = require(`./build/${common.buildType}/binding`); +} catch { + console.error(`${__filename}: Binding failed to load`); + process.exit(0); +} + +const bench = common.createBenchmark(main, { + n: [1e5, 1e6, 1e7], +}); + +function main({ n }) { + binding.checkObjectTag(n, bench, bench.start, bench.end); +} diff --git a/benchmark/napi/type-tag/index.js b/benchmark/napi/type-tag/index.js new file mode 100644 index 00000000000000..3f85b9af8e7d59 --- /dev/null +++ b/benchmark/napi/type-tag/index.js @@ -0,0 +1,18 @@ +'use strict'; +const common = require('../../common.js'); + +let binding; +try { + binding = require(`./build/${common.buildType}/binding`); +} catch { + console.error(`${__filename}: Binding failed to load`); + process.exit(0); +} + +const bench = common.createBenchmark(main, { + n: [1e3, 1e4, 1e5], +}); + +function main({ n }) { + binding.tagObject(n, bench, bench.start, bench.end); +} diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 489e0929485787..c40e23811e099a 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -596,6 +596,27 @@ minimum lifetimes explicitly. For more details, review the [Object lifetime management][]. +#### napi_type_tag + + +A 128-bit value stored as two unsigned 64-bit integers. It serves as a UUID +with which JavaScript objects can be "tagged" in order to ensure that they are +of a certain type. This is a stronger check than [`napi_instanceof`][], because +the latter can report a false positive if the object's prototype has been +manipulated. Type-tagging is most useful in conjunction with [`napi_wrap`][] +because it ensures that the pointer retrieved from a wrapped object can be +safely cast to the native type corresponding to the type tag that had been +previously applied to the JavaScript object. + +```c +typedef struct { + uint64_t lower; + uint64_t upper; +} napi_type_tag; +``` + ### N-API callback types #### napi_callback_info @@ -4276,6 +4297,143 @@ if (is_instance) { The reference must be freed once it is no longer needed. +There are occasions where `napi_instanceof()` is insufficient for ensuring that +a JavaScript object is a wrapper for a certain native type. This is the case +especially when wrapped JavaScript objects are passed back into the addon via +static methods rather than as the `this` value of prototype methods. In such +cases there is a chance that they may be unwrapped incorrectly. + +```js +const myAddon = require('./build/Release/my_addon.node'); + +// `openDatabase()` returns a JavaScript object that wraps a native database +// handle. +const dbHandle = myAddon.openDatabase(); + +// `query()` returns a JavaScript object that wraps a native query handle. +const queryHandle = myAddon.query(dbHandle, 'Gimme ALL the things!'); + +// There is an accidental error in the line below. The first parameter to +// `myAddon.queryHasRecords()` should be the database handle (`dbHandle`), not +// the query handle (`query`), so the correct condition for the while-loop +// should be +// +// myAddon.queryHasRecords(dbHandle, queryHandle) +// +while (myAddon.queryHasRecords(queryHandle, dbHandle)) { + // retrieve records +} +``` + +In the above example `myAddon.queryHasRecords()` is a method that accepts two +arguments. The first is a database handle and the second is a query handle. +Internally, it unwraps the first argument and casts the resulting pointer to a +native database handle. It then unwraps the second argument and casts the +resulting pointer to a query handle. If the arguments are passed in the wrong +order, the casts will work, however, there is a good chance that the underlying +database operation will fail, or will even cause an invalid memory access. + +To ensure that the pointer retrieved from the first argument is indeed a pointer +to a database handle and, similarly, that the pointer retrieved from the second +argument is indeed a pointer to a query handle, the implementation of +`queryHasRecords()` has to perform a type validation. Retaining the JavaScript +class constructor from which the database handle was instantiated and the +constructor from which the query handle was instantiated in `napi_ref`s can +help, because `napi_instanceof()` can then be used to ensure that the instances +passed into `queryHashRecords()` are indeed of the correct type. + +Unfortunately, `napi_instanceof()` does not protect against prototype +manipulation. For example, the prototype of the database handle instance can be +set to the prototype of the constructor for query handle instances. In this +case, the database handle instance can appear as a query handle instance, and it +will pass the `napi_instanceof()` test for a query handle instance, while still +containing a pointer to a database handle. + +To this end, N-API provides type-tagging capabilities. + +A type tag is a 128-bit integer unique to the addon. N-API provides the +`napi_type_tag` structure for storing a type tag. When such a value is passed +along with a JavaScript object stored in a `napi_value` to +`napi_type_tag_object()`, the JavaScript object will be "marked" with the +type tag. The "mark" is invisible on the JavaScript side. When a JavaScript +object arrives into a native binding, `napi_check_object_type_tag()` can be used +along with the original type tag to determine whether the JavaScript object was +previously "marked" with the type tag. This creates a type-checking capability +of a higher fidelity than `napi_instanceof()` can provide, because such type- +tagging survives prototype manipulation and addon unloading/reloading. + +Continuing the above example, the following skeleton addon implementation +illustrates the use of `napi_type_tag_object()` and +`napi_check_object_type_tag()`. + +```c +// This value is the type tag for a database handle. The command +// +// uuidgen | sed -r -e 's/-//g' -e 's/(.{16})(.*)/0x\1, 0x\2/' +// +// can be used to obtain the two values with which to initialize the structure. +static const napi_type_tag DatabaseHandleTypeTag = { + 0x1edf75a38336451d, 0xa5ed9ce2e4c00c38 +}; + +// This value is the type tag for a query handle. +static const napi_type_tag QueryHandleTypeTag = { + 0x9c73317f9fad44a3, 0x93c3920bf3b0ad6a +}; + +static napi_value +openDatabase(napi_env env, napi_callback_info info) { + napi_status status; + napi_value result; + + // Perform the underlying action which results in a database handle. + DatabaseHandle* dbHandle = open_database(); + + // Create a new, empty JS object. + status = napi_create_object(env, &result); + if (status != napi_ok) return NULL; + + // Tag the object to indicate that it holds a pointer to a `DatabaseHandle`. + status = napi_type_tag_object(env, result, &DatabaseHandleTypeTag); + if (status != napi_ok) return NULL; + + // Store the pointer to the `DatabaseHandle` structure inside the JS object. + status = napi_wrap(env, result, dbHandle, NULL, NULL, NULL); + if (status != napi_ok) return NULL; + + return result; +} + +// Later when we receive a JavaScript object purporting to be a database handle +// we can use `napi_check_object_type_tag()` to ensure that it is indeed such a +// handle. + +static napi_value +query(napi_env env, napi_callback_info info) { + napi_status status; + size_t argc = 2; + napi_value argv[2]; + bool is_db_handle; + + status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); + if (status != napi_ok) return NULL; + + // Check that the object passed as the first parameter has the previously + // applied tag. + status = napi_check_object_type_tag(env, + argv[0], + &DatabaseHandleTypeTag, + &is_db_handle); + if (status != napi_ok) return NULL; + + // Throw a `TypeError` if it doesn't. + if (!is_db_handle) { + // Throw a TypeError. + return NULL; + } +} +``` + ### napi_define_class + +> Stability: 1 - Experimental + +```c +napi_status napi_type_tag_object(napi_env env, + napi_value js_object, + const napi_type_tag* type_tag); +``` + +* `[in] env`: The environment that the API is invoked under. +* `[in] js_object`: The JavaScript object to be marked. +* `[in] type_tag`: The tag with which the object is to be marked. + +Returns `napi_ok` if the API succeeded. + +Associates the value of the `type_tag` pointer with the JavaScript object. +`napi_check_object_type_tag()` can then be used to compare the tag that was +attached to the object with one owned by the addon to ensure that the object +has the right type. + +If the object already has an associated type tag, this API will return +`napi_invalid_arg`. + +### napi_check_object_type_tag + + +> Stability: 1 - Experimental + +```c +napi_status napi_check_object_type_tag(napi_env env, + napi_value js_object, + const napi_type_tag* type_tag, + bool* result); +``` + +* `[in] env`: The environment that the API is invoked under. +* `[in] js_object`: The JavaScript object whose type tag to examine. +* `[in] type_tag`: The tag with which to compare any tag found on the object. +* `[out] result`: Whether the type tag given matched the type tag on the +object. `false` is also returned if no type tag was found on the object. + +Returns `napi_ok` if the API succeeded. + +Compares the pointer given as `type_tag` with any that can be found on +`js_object`. If no tag is found on `js_object` or, if a tag is found but it does +not match `type_tag`, then `result` is set to `false`. If a tag is found and it +matches `type_tag`, then `result` is set to `true`. + ### napi_add_finalizer -Addons are dynamically-linked shared objects written in C++. The -[`require()`][require] function can load Addons as ordinary Node.js modules. +_Addons_ are dynamically-linked shared objects written in C++. The +[`require()`][require] function can load addons as ordinary Node.js modules. Addons provide an interface between JavaScript and C/C++ libraries. -There are three options for implementing Addons: N-API, nan, or direct +There are three options for implementing addons: N-API, nan, or direct use of internal V8, libuv and Node.js libraries. Unless there is a need for direct access to functionality which is not exposed by N-API, use N-API. -Refer to [C/C++ Addons with N-API](n-api.html) for more information on N-API. +Refer to [C/C++ addons with N-API](n-api.html) for more information on N-API. -When not using N-API, implementing Addons is complicated, +When not using N-API, implementing addons is complicated, involving knowledge of several components and APIs: * V8: the C++ library Node.js uses to provide the @@ -27,27 +27,27 @@ involving knowledge of several components and APIs: access across all major operating systems to many common system tasks, such as interacting with the filesystem, sockets, timers, and system events. libuv also provides a pthreads-like threading abstraction that may be used to - power more sophisticated asynchronous Addons that need to move beyond the + power more sophisticated asynchronous addons that need to move beyond the standard event loop. Addon authors are encouraged to think about how to avoid blocking the event loop with I/O or other time-intensive tasks by off-loading work via libuv to non-blocking system operations, worker threads or a custom use of libuv's threads. -* Internal Node.js libraries. Node.js itself exports C++ APIs that Addons can +* Internal Node.js libraries. Node.js itself exports C++ APIs that addons can use, the most important of which is the `node::ObjectWrap` class. * Node.js includes other statically linked libraries including OpenSSL. These other libraries are located in the `deps/` directory in the Node.js source tree. Only the libuv, OpenSSL, V8 and zlib symbols are purposefully - re-exported by Node.js and may be used to various extents by Addons. See + re-exported by Node.js and may be used to various extents by addons. See [Linking to libraries included with Node.js][] for additional information. All of the following examples are available for [download][] and may -be used as the starting-point for an Addon. +be used as the starting-point for an addon. ## Hello world -This "Hello world" example is a simple Addon, written in C++, that is the +This "Hello world" example is a simple addon, written in C++, that is the equivalent of the following JavaScript code: ```js @@ -84,7 +84,7 @@ NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize) } // namespace demo ``` -All Node.js Addons must export an initialization function following +All Node.js addons must export an initialization function following the pattern: ```cpp @@ -315,7 +315,7 @@ Once the source code has been written, it must be compiled into the binary `addon.node` file. To do so, create a file called `binding.gyp` in the top-level of the project describing the build configuration of the module using a JSON-like format. This file is used by [node-gyp][], a tool written -specifically to compile Node.js Addons. +specifically to compile Node.js addons. ```json { @@ -331,7 +331,7 @@ specifically to compile Node.js Addons. A version of the `node-gyp` utility is bundled and distributed with Node.js as part of `npm`. This version is not made directly available for developers to use and is intended only to support the ability to use the -`npm install` command to compile and install Addons. Developers who wish to +`npm install` command to compile and install addons. Developers who wish to use `node-gyp` directly can install it using the command `npm install -g node-gyp`. See the `node-gyp` [installation instructions][] for more information, including platform-specific requirements. @@ -344,11 +344,11 @@ will generate either a `Makefile` (on Unix platforms) or a `vcxproj` file Next, invoke the `node-gyp build` command to generate the compiled `addon.node` file. This will be put into the `build/Release/` directory. -When using `npm install` to install a Node.js Addon, npm uses its own bundled +When using `npm install` to install a Node.js addon, npm uses its own bundled version of `node-gyp` to perform this same set of actions, generating a -compiled version of the Addon for the user's platform on demand. +compiled version of the addon for the user's platform on demand. -Once built, the binary Addon can be used from within Node.js by pointing +Once built, the binary addon can be used from within Node.js by pointing [`require()`][require] to the built `addon.node` module: ```js @@ -359,12 +359,12 @@ console.log(addon.hello()); // Prints: 'world' ``` -Because the exact path to the compiled Addon binary can vary depending on how -it is compiled (i.e. sometimes it may be in `./build/Debug/`), Addons can use +Because the exact path to the compiled addon binary can vary depending on how +it is compiled (i.e. sometimes it may be in `./build/Debug/`), addons can use the [bindings][] package to load the compiled module. While the `bindings` package implementation is more sophisticated in how it -locates Addon modules, it is essentially using a `try…catch` pattern similar to: +locates addon modules, it is essentially using a `try…catch` pattern similar to: ```js try { @@ -377,7 +377,7 @@ try { ### Linking to libraries included with Node.js Node.js uses statically linked libraries such as V8, libuv and OpenSSL. All -Addons are required to link to V8 and may link to any of the other dependencies +addons are required to link to V8 and may link to any of the other dependencies as well. Typically, this is as simple as including the appropriate `#include <...>` statements (e.g. `#include `) and `node-gyp` will locate the appropriate headers automatically. However, there are a few caveats to be @@ -385,23 +385,23 @@ aware of: * When `node-gyp` runs, it will detect the specific release version of Node.js and download either the full source tarball or just the headers. If the full -source is downloaded, Addons will have complete access to the full set of +source is downloaded, addons will have complete access to the full set of Node.js dependencies. However, if only the Node.js headers are downloaded, then only the symbols exported by Node.js will be available. * `node-gyp` can be run using the `--nodedir` flag pointing at a local Node.js -source image. Using this option, the Addon will have access to the full set of +source image. Using this option, the addon will have access to the full set of dependencies. ### Loading addons using `require()` -The filename extension of the compiled Addon binary is `.node` (as opposed +The filename extension of the compiled addon binary is `.node` (as opposed to `.dll` or `.so`). The [`require()`][require] function is written to look for files with the `.node` file extension and initialize those as dynamically-linked libraries. When calling [`require()`][require], the `.node` extension can usually be -omitted and Node.js will still find and initialize the Addon. One caveat, +omitted and Node.js will still find and initialize the addon. One caveat, however, is that Node.js will first attempt to locate and load modules or JavaScript files that happen to share the same base name. For instance, if there is a file `addon.js` in the same directory as the binary `addon.node`, @@ -411,15 +411,15 @@ and load it instead. ## Native abstractions for Node.js Each of the examples illustrated in this document make direct use of the -Node.js and V8 APIs for implementing Addons. The V8 API can, and has, changed +Node.js and V8 APIs for implementing addons. The V8 API can, and has, changed dramatically from one V8 release to the next (and one major Node.js release to -the next). With each change, Addons may need to be updated and recompiled in +the next). With each change, addons may need to be updated and recompiled in order to continue functioning. The Node.js release schedule is designed to minimize the frequency and impact of such changes but there is little that Node.js can do to ensure stability of the V8 APIs. The [Native Abstractions for Node.js][] (or `nan`) provide a set of tools that -Addon developers are recommended to use to keep compatibility between past and +addon developers are recommended to use to keep compatibility between past and future releases of V8 and Node.js. See the `nan` [examples][] for an illustration of how it can be used. @@ -427,10 +427,10 @@ illustration of how it can be used. > Stability: 2 - Stable -N-API is an API for building native Addons. It is independent from +N-API is an API for building native addons. It is independent from the underlying JavaScript runtime (e.g. V8) and is maintained as part of Node.js itself. This API will be Application Binary Interface (ABI) stable -across versions of Node.js. It is intended to insulate Addons from +across versions of Node.js. It is intended to insulate addons from changes in the underlying JavaScript engine and allow modules compiled for one version to run on later versions of Node.js without recompilation. Addons are built/packaged with the same approach/tools @@ -479,11 +479,11 @@ NAPI_MODULE(NODE_GYP_MODULE_NAME, init) ``` The functions available and how to use them are documented in -[C/C++ Addons with N-API](n-api.html). +[C/C++ addons with N-API](n-api.html). ## Addon examples -Following are some example Addons intended to help developers get started. The +Following are some example addons intended to help developers get started. The examples make use of the V8 APIs. Refer to the online [V8 reference][v8-docs] for help with the various V8 calls, and V8's [Embedder's Guide][] for an explanation of several concepts used such as handles, scopes, function @@ -509,7 +509,7 @@ filename to the `sources` array: "sources": ["addon.cc", "myexample.cc"] ``` -Once the `binding.gyp` file is ready, the example Addons can be configured and +Once the `binding.gyp` file is ready, the example addons can be configured and built using `node-gyp`: ```console @@ -583,7 +583,7 @@ NODE_MODULE(NODE_GYP_MODULE_NAME, Init) } // namespace demo ``` -Once compiled, the example Addon can be required and used from within Node.js: +Once compiled, the example addon can be required and used from within Node.js: ```js // test.js @@ -594,7 +594,7 @@ console.log('This should be eight:', addon.add(3, 5)); ### Callbacks -It is common practice within Addons to pass JavaScript functions to a C++ +It is common practice within addons to pass JavaScript functions to a C++ function and execute them from there. The following example illustrates how to invoke such callbacks: @@ -635,7 +635,7 @@ NODE_MODULE(NODE_GYP_MODULE_NAME, Init) ``` This example uses a two-argument form of `Init()` that receives the full -`module` object as the second argument. This allows the Addon to completely +`module` object as the second argument. This allows the addon to completely overwrite `exports` with a single function instead of adding the function as a property of `exports`. From f393ae929628f879aa966f8c84345faa8b4859c5 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 28 Jul 2020 21:42:36 -0700 Subject: [PATCH 14/79] doc: simplify and clarify console.assert() documentation PR-URL: https://github.com/nodejs/node/pull/34544 Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat Reviewed-By: Luigi Pinca --- doc/api/console.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/api/console.md b/doc/api/console.md index 3baac4bdac0da8..9e4548581b5f70 100644 --- a/doc/api/console.md +++ b/doc/api/console.md @@ -150,24 +150,23 @@ changes: * `value` {any} The value tested for being truthy. * `...message` {any} All arguments besides `value` are used as error message. -A simple assertion test that verifies whether `value` is truthy. If it is not, -or `value` is not passed, -`Assertion failed` is logged. If provided, the error `message` is formatted -using [`util.format()`][] by passing along all message arguments. The output is -used as the error message. +`console.assert()` writes a message if `value` is [falsy][] or omitted. It only +writes a message and does not otherwise affect execution. The output always +starts with `"Assertion failed"`. If provided, `message` is formatted using +[`util.format()`][]. + +If `value` is [truthy][], nothing happens. ```js console.assert(true, 'does nothing'); -// OK + console.assert(false, 'Whoops %s work', 'didn\'t'); // Assertion failed: Whoops didn't work + console.assert(); // Assertion failed ``` -Calling `console.assert()` with a falsy assertion will only cause the `message` -to be printed to the console without interrupting execution of subsequent code. - ### `console.clear()` From 4af5dbd3bf8feea8e844dc7563413425a782f83b Mon Sep 17 00:00:00 2001 From: Mary Marchini Date: Fri, 31 Jul 2020 16:14:41 -0700 Subject: [PATCH 16/79] build: fix auto-start-ci script path PR-URL: https://github.com/nodejs/node/pull/34588 Reviewed-By: Rich Trott Reviewed-By: Richard Lau --- .github/workflows/auto-start-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/auto-start-ci.yml b/.github/workflows/auto-start-ci.yml index d4c364e2bb2f52..826b80caef0c58 100644 --- a/.github/workflows/auto-start-ci.yml +++ b/.github/workflows/auto-start-ci.yml @@ -62,4 +62,4 @@ jobs: ncu-config set repo ${{ env.REPOSITORY }} - name: Start CI - run: ./tools/start-ci.sh ${{ secrets.GITHUB_TOKEN }} ${{ env.OWNER }} ${{ env.REPOSITORY }} $(echo '${{ steps.get_prs_for_ci.outputs.data }}' | jq '.repository.pullRequests.nodes | map(.number) | .[]') + run: ./tools/actions/start-ci.sh ${{ secrets.GITHUB_TOKEN }} ${{ env.OWNER }} ${{ env.REPOSITORY }} $(echo '${{ steps.get_prs_for_ci.outputs.data }}' | jq '.repository.pullRequests.nodes | map(.number) | .[]') From befbaf384edad0f5569c761981e590372a008a9a Mon Sep 17 00:00:00 2001 From: Mary Marchini Date: Fri, 31 Jul 2020 17:01:21 -0700 Subject: [PATCH 17/79] build: don't run auto-start-ci on push PR-URL: https://github.com/nodejs/node/pull/34588 Reviewed-By: Rich Trott Reviewed-By: Richard Lau --- .github/workflows/auto-start-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/auto-start-ci.yml b/.github/workflows/auto-start-ci.yml index 826b80caef0c58..b6be44b6e9c65d 100644 --- a/.github/workflows/auto-start-ci.yml +++ b/.github/workflows/auto-start-ci.yml @@ -2,7 +2,6 @@ name: Auto Start CI on: - push: schedule: # `schedule` event is used instead of `pull_request` because when a # `pull_requesst` event is triggered on a PR from a fork, GITHUB_TOKEN will From 44e6c010b45fd36e64868fb97a547ca4c21d691e Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Tue, 7 Jul 2020 09:32:01 -0400 Subject: [PATCH 18/79] esm: fix hook mistypes and links to types Prior to this commit, the custom loader hooks were: * missing the Node.js API ref docs types * missing the function signature from their sections * linking directly to the specification (not customary) * had an inconsistent non-nullable JSDoc promise return * had JSDoc object properties that weren't alpha-sorted * designated set of non-nullable types when single was fine Notes: https://www.typescriptlang.org/play/index.html?strictNullChecks=true&useJavaScript=true#code/PQKhCgAIUgBAHAhgJ0QW0gbwM4BdkCWAdgOYC+k28ApgMYEBmB1yUMCK6WmbkftAeyIATArgJDsALkgBCAILJUATwA8eQqQB8AGl58kyakVwBVAEoAZGbIAUG4iUgAfSAFcR1JkWrCAlHrQkGQUgibUAB64vByoGJgAYh604kIUwl6IbgA2uObU2ALZAG7UMUa4bshE2FgACsgCaATY1KqY7sjZMg6kwVpkbMDgkfACyLiQiNjKRLSQDMmpRJBGhSXU9jT0TCw6kGG4kbj7GQxZufnrpX5YUAeSkx2GxmZWkAC8kEQ52cGfD3CUQA3PdGJBbABZRC4AAWADpUCImrZblpIAAGeEAVluHWAwEgAGUmtRAaJlvD7nwCZAEuNKKTIAzENk-lQ6IxmMhsKcBIy0GTaG48E1INkBCQCPMGAy1kVio4qXwaYT5NkAO6IZS1CpVFaIFYCABGACs6JMBAxIHCybLkPEqt1IOp8I4BsqVXrqncVSqnTIXiYLJZIAB+al+77UDWQENbTm7ZD7INvSx+eGwozWqSRv0+WPxjk7bkZrNeQIqsigviDPjgqEwhFI4Qo26qTE4vGQWnyIgCW3IcliCRET2qyAAdVhxgOrOyjkgAAMzhc8gUFdQl-tbVNkCQ3IKTLVaIbIMayWgBKJdsJ4ZAAJIrOEtSO00+tSBiADktUQwlEPpDQHGch2KVk3DtBk0BhWhYUXMIKVHVlIFGcZcGwcdVmoSofVXHJ12uTZiy5PZfSjeFKMOY5Kz9RCR0kGQAG1KPhaiojYoQkMkfZv2AwcAFp6OWb8AF1aOCPwa2Ce5aQAES8FgbX5AA5a9qHhU1antKY2WZQdKG2UieU9b0Vnwy4Nw2BMSzI9iTkgCzCM3KTwDIIA https://closure-compiler.appspot.com/home#code%3D%252F%252F%2520%253D%253DClosureCompiler%253D%253D%250A%252F%252F%2520%2540compilation_level%2520ADVANCED_OPTIMIZATIONS%250A%252F%252F%2520%2540warning_level%2520VERBOSE%250A%252F%252F%2520%2540jscomp_error%2520strictCheckTypes%250A%252F%252F%2520%2540language_out%2520ECMASCRIPT_NEXT%250A%252F%252F%2520%2540checks_only%250A%252F%252F%2520%253D%253D%252FClosureCompiler%253D%253D%250A%250A%252F**%250A%2520*%2520%2540param%2520%257Bstring%257D%2520specifier%250A%2520*%2520%2540param%2520%257B%257B%250A%2520*%2520%2520%2520conditions%253A%2520!Array%253Cstring%253E%252C%250A%2520*%2520%2520%2520parentURL%253A%2520!(string%2520%257C%2520undefined)%252C%250A%2520*%2520%257D%257D%2520context%250A%2520*%2520%2540param%2520%257BFunction%257D%2520defaultResolve%250A%2520*%2520%2540returns%2520%257BPromise%253C%257B%2520url%253A%2520string%2520%257D%253E%257D%250A%2520*%252F%250Aexport%2520async%2520function%2520resolve(specifier%252C%2520context%252C%2520defaultResolve)%2520%257B%250A%2520%2520const%2520%257B%2520parentURL%2520%253D%2520null%2520%257D%2520%253D%2520context%253B%250A%2520%2520if%2520(Math.random()%2520%253E%25200.5)%2520%257B%2520%252F%252F%2520Some%2520condition.%250A%2520%2520%2520%2520%252F%252F%2520For%2520some%2520or%2520all%2520specifiers%252C%2520do%2520some%2520custom%2520logic%2520for%2520resolving.%250A%2520%2520%2520%2520%252F%252F%2520Always%2520return%2520an%2520object%2520of%2520the%2520form%2520%257Burl%253A%2520%253Cstring%253E%257D.%250A%2520%2520%2520%2520return%2520%257B%250A%2520%2520%2520%2520%2520%2520url%253A%2520parentURL%2520%253F%250A%2520%2520%2520%2520%2520%2520%2520%2520new%2520URL(specifier%252C%2520parentURL).href%2520%253A%250A%2520%2520%2520%2520%2520%2520%2520%2520new%2520URL(specifier).href%252C%250A%2520%2520%2520%2520%257D%253B%250A%2520%2520%257D%250A%2520%2520if%2520(Math.random()%2520%253C%25200.5)%2520%257B%2520%252F%252F%2520Another%2520condition.%250A%2520%2520%2520%2520%252F%252F%2520When%2520calling%2520%2560defaultResolve%2560%252C%2520the%2520arguments%2520can%2520be%2520modified.%2520In%2520this%250A%2520%2520%2520%2520%252F%252F%2520case%2520it's%2520adding%2520another%2520value%2520for%2520matching%2520conditional%2520exports.%250A%2520%2520%2520%2520return%2520defaultResolve(specifier%252C%2520%257B%250A%2520%2520%2520%2520%2520%2520...context%252C%250A%2520%2520%2520%2520%2520%2520conditions%253A%2520%255B...context.conditions%252C%2520'another-condition'%255D%252C%250A%2520%2520%2520%2520%257D)%253B%250A%2520%2520%257D%250A%2520%2520%252F%252F%2520Defer%2520to%2520Node.js%2520for%2520all%2520other%2520specifiers.%250A%2520%2520return%2520defaultResolve(specifier%252C%2520context%252C%2520defaultResolve)%253B%250A%257D PR-URL: https://github.com/nodejs/node/pull/34240 Reviewed-By: Rich Trott Reviewed-By: Guy Bedford --- doc/api/esm.md | 83 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 27 deletions(-) diff --git a/doc/api/esm.md b/doc/api/esm.md index c9bb7473a8e689..e98cae376f6c5b 100644 --- a/doc/api/esm.md +++ b/doc/api/esm.md @@ -1184,11 +1184,19 @@ CommonJS modules loaded. ### Hooks -#### resolve hook +#### `resolve(specifier, context, defaultResolve)` > Note: The loaders API is being redesigned. This hook may disappear or its > signature may change. Do not rely on the API described below. +* `specifier` {string} +* `context` {Object} + * `conditions` {string[]} + * `parentURL` {string} +* `defaultResolve` {Function} +* Returns: {Object} + * `url` {string} + The `resolve` hook returns the resolved file URL for a given module specifier and parent URL. The module specifier is the string in an `import` statement or `import()` expression, and the parent URL is the URL of the module that imported @@ -1209,11 +1217,11 @@ Node.js module specifier resolution behavior_ when calling `defaultResolve`, the /** * @param {string} specifier * @param {{ + * conditions: !Array, * parentURL: !(string | undefined), - * conditions: !(Array), * }} context * @param {Function} defaultResolve - * @returns {!(Promise<{ url: string }>)} + * @returns {Promise<{ url: string }>} */ export async function resolve(specifier, context, defaultResolve) { const { parentURL = null } = context; @@ -1239,29 +1247,34 @@ export async function resolve(specifier, context, defaultResolve) { } ``` -#### getFormat hook +#### `getFormat(url, context, defaultGetFormat)` > Note: The loaders API is being redesigned. This hook may disappear or its > signature may change. Do not rely on the API described below. +* `url` {string} +* `context` {Object} +* `defaultGetFormat` {Function} +* Returns: {Object} + * `format` {string} + The `getFormat` hook provides a way to define a custom method of determining how a URL should be interpreted. The `format` returned also affects what the acceptable forms of source values are for a module when parsing. This can be one of the following: -| `format` | Description | Acceptable Types For `source` Returned by `getSource` or `transformSource` | -| --- | --- | --- | -| `'builtin'` | Load a Node.js builtin module | Not applicable | -| `'commonjs'` | Load a Node.js CommonJS module | Not applicable | -| `'json'` | Load a JSON file | { [ArrayBuffer][], [string][], [TypedArray][] } | -| `'module'` | Load an ES module | { [ArrayBuffer][], [string][], [TypedArray][] } | -| `'wasm'` | Load a WebAssembly module | { [ArrayBuffer][], [string][], [TypedArray][] } | +| `format` | Description | Acceptable Types For `source` Returned by `getSource` or `transformSource` | +| ------------ | ------------------------------ | -------------------------------------------------------------------------- | +| `'builtin'` | Load a Node.js builtin module | Not applicable | +| `'commonjs'` | Load a Node.js CommonJS module | Not applicable | +| `'json'` | Load a JSON file | { [`string`][], [`ArrayBuffer`][], [`TypedArray`][] } | +| `'module'` | Load an ES module | { [`string`][], [`ArrayBuffer`][], [`TypedArray`][] } | +| `'wasm'` | Load a WebAssembly module | { [`ArrayBuffer`][], [`TypedArray`][] } | Note: These types all correspond to classes defined in ECMAScript. -* The specific [ArrayBuffer][] object is a [SharedArrayBuffer][]. -* The specific [string][] object is not the class constructor, but an instance. -* The specific [TypedArray][] object is a [Uint8Array][]. +* The specific [`ArrayBuffer`][] object is a [`SharedArrayBuffer`][]. +* The specific [`TypedArray`][] object is a [`Uint8Array`][]. Note: If the source value of a text-based format (i.e., `'json'`, `'module'`) is not a string, it will be converted to a string using [`util.TextDecoder`][]. @@ -1287,11 +1300,18 @@ export async function getFormat(url, context, defaultGetFormat) { } ``` -#### getSource hook +#### `getSource(url, context, defaultGetSource)` > Note: The loaders API is being redesigned. This hook may disappear or its > signature may change. Do not rely on the API described below. +* `url` {string} +* `context` {Object} + * `format` {string} +* `defaultGetSource` {Function} +* Returns: {Object} + * `source` {string|SharedArrayBuffer|Uint8Array} + The `getSource` hook provides a way to define a custom method for retrieving the source code of an ES module specifier. This would allow a loader to potentially avoid reading files from disk. @@ -1301,7 +1321,7 @@ potentially avoid reading files from disk. * @param {string} url * @param {{ format: string }} context * @param {Function} defaultGetSource - * @returns {Promise<{ source: !(SharedArrayBuffer | string | Uint8Array) }>} + * @returns {Promise<{ source: !(string | SharedArrayBuffer | Uint8Array) }>} */ export async function getSource(url, context, defaultGetSource) { const { format } = context; @@ -1317,11 +1337,18 @@ export async function getSource(url, context, defaultGetSource) { } ``` -#### transformSource hook +#### `transformSource(source, context, defaultTransformSource)` > Note: The loaders API is being redesigned. This hook may disappear or its > signature may change. Do not rely on the API described below. +* `source` {string|SharedArrayBuffer|Uint8Array} +* `context` {Object} + * `format` {string} + * `url` {string} +* Returns: {Object} + * `source` {string|SharedArrayBuffer|Uint8Array} + The `transformSource` hook provides a way to modify the source code of a loaded ES module file after the source string has been loaded but before Node.js has done anything with it. @@ -1332,13 +1359,13 @@ unknown-to-Node.js file extensions. See the [transpiler loader example][] below. ```js /** - * @param {!(SharedArrayBuffer | string | Uint8Array)} source + * @param {!(string | SharedArrayBuffer | Uint8Array)} source * @param {{ - * url: string, * format: string, + * url: string, * }} context * @param {Function} defaultTransformSource - * @returns {Promise<{ source: !(SharedArrayBuffer | string | Uint8Array) }>} + * @returns {Promise<{ source: !(string | SharedArrayBuffer | Uint8Array) }>} */ export async function transformSource(source, context, defaultTransformSource) { const { url, format } = context; @@ -1354,11 +1381,13 @@ export async function transformSource(source, context, defaultTransformSource) { } ``` -#### getGlobalPreloadCode hook +#### `getGlobalPreloadCode()` > Note: The loaders API is being redesigned. This hook may disappear or its > signature may change. Do not rely on the API described below. +* Returns: {string} + Sometimes it can be necessary to run some code inside of the same global scope that the application will run in. This hook allows to return a string that will be ran as sloppy-mode script on startup. @@ -1909,12 +1938,12 @@ success! [`import`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import [`module.createRequire()`]: modules.html#modules_module_createrequire_filename [`module.syncBuiltinESMExports()`]: modules.html#modules_module_syncbuiltinesmexports -[`transformSource` hook]: #esm_code_transformsource_code_hook -[ArrayBuffer]: https://www.ecma-international.org/ecma-262/6.0/#sec-arraybuffer-constructor -[SharedArrayBuffer]: https://tc39.es/ecma262/#sec-sharedarraybuffer-constructor -[string]: https://www.ecma-international.org/ecma-262/6.0/#sec-string-constructor -[TypedArray]: https://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects -[Uint8Array]: https://www.ecma-international.org/ecma-262/6.0/#sec-uint8array +[`transformSource` hook]: #esm_transformsource_source_context_defaulttransformsource +[`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer +[`SharedArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer +[`string`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String +[`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray +[`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array [`util.TextDecoder`]: util.html#util_class_util_textdecoder [import an ES or CommonJS module for its side effects only]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Import_a_module_for_its_side_effects_only [special scheme]: https://url.spec.whatwg.org/#special-scheme From c4457d873ffa6b04c51a7e6d3cac500045ea30b3 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 27 Jul 2020 01:11:38 +0200 Subject: [PATCH 19/79] benchmark: always throw the same Error instance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stack trace capturing currently accounts for 40 % of the benchmark running time. Always throwing the same exception object removes that overhead and lets the benchmark be more focused on what it is supposed to measure. Refs: https://github.com/nodejs/node/pull/34512#issuecomment-663977271 PR-URL: https://github.com/nodejs/node/pull/34523 Reviewed-By: Michaël Zasso Reviewed-By: Andrey Pechkurov Reviewed-By: Ruben Bridgewater Reviewed-By: Luigi Pinca Reviewed-By: Gerhard Stöbich --- benchmark/async_hooks/promises.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benchmark/async_hooks/promises.js b/benchmark/async_hooks/promises.js index 9927ec0dc504e9..d60ae70192c8cb 100644 --- a/benchmark/async_hooks/promises.js +++ b/benchmark/async_hooks/promises.js @@ -37,10 +37,11 @@ const bench = common.createBenchmark(main, { ] }); +const err = new Error('foobar'); async function run(n) { for (let i = 0; i < n; i++) { await new Promise((resolve) => resolve()) - .then(() => { throw new Error('foobar'); }) + .then(() => { throw err; }) .catch((e) => e); } } From 335cb0d1d1a72ca016b9b6a7ad258dfeecef390d Mon Sep 17 00:00:00 2001 From: Gireesh Punathil Date: Sun, 26 Jul 2020 09:51:51 -0400 Subject: [PATCH 20/79] lib: absorb `path` error cases Absorb low level libuv failure in the process initialization phase Fixes: https://github.com/nodejs/node/issues/33759 Refs: https://github.com/nodejs/node/issues/33759#issuecomment-663980558 PR-URL: https://github.com/nodejs/node/pull/34519 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca Reviewed-By: Zeyu Yang Reviewed-By: Harshitha K P --- lib/internal/bootstrap/pre_execution.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/bootstrap/pre_execution.js index e227e7853f5462..dfbefa955cab8a 100644 --- a/lib/internal/bootstrap/pre_execution.js +++ b/lib/internal/bootstrap/pre_execution.js @@ -92,7 +92,9 @@ function patchProcessObject(expandArgv1) { if (expandArgv1 && process.argv[1] && !process.argv[1].startsWith('-')) { // Expand process.argv[1] into a full path. const path = require('path'); - process.argv[1] = path.resolve(process.argv[1]); + try { + process.argv[1] = path.resolve(process.argv[1]); + } catch {} } // TODO(joyeecheung): most of these should be deprecated and removed, From e2bea73b0362a95fcf1679eb6e2dfe605bf328ef Mon Sep 17 00:00:00 2001 From: Michael Dawson Date: Mon, 13 Jul 2020 16:44:06 -0400 Subject: [PATCH 21/79] doc: clarify N-API version 1 Refs: https://github.com/nodejs/node-addon-api/issues/760 Clarify which version of 8.x in which N-API version 1 matches the shape in later versions like 10.x Signed-off-by: Michael Dawson PR-URL: https://github.com/nodejs/node/pull/34344 Reviewed-By: Gus Caplan Reviewed-By: Gabriel Schulhof --- doc/api/n-api.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index c40e23811e099a..d5f96d015105a7 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -240,19 +240,25 @@ from version 3 with some additions. This means that it is not necessary to recompile for new versions of Node.js which are listed as supporting a later version. -| | 1 | 2 | 3 | 4 | 5 | 6 | -|-------|---------|----------|----------|----------|-----------|-----------| -| v6.x | | | v6.14.2* | | | | -| v8.x | v8.0.0* | v8.10.0* | v8.11.2 | v8.16.0 | | | -| v9.x | v9.0.0* | v9.3.0* | v9.11.0* | | | | -| v10.x | v10.0.0 | v10.0.0 | v10.0.0 | v10.16.0 | v10.17.0 | v10.20.0 | -| v11.x | v11.0.0 | v11.0.0 | v11.0.0 | v11.8.0 | | | -| v12.x | v12.0.0 | v12.0.0 | v12.0.0 | v12.0.0 | v12.11.0 | | -| v13.x | v13.0.0 | v13.0.0 | v13.0.0 | v13.0.0 | v13.0.0 | | -| v14.x | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | +| | 1 | 2 | 3 | 4 | 5 | 6 | +|-------|----------|----------|----------|----------|-----------|-----------| +| v6.x | | | v6.14.2* | | | | +| v8.x | v8.6.0** | v8.10.0* | v8.11.2 | v8.16.0 | | | +| v9.x | v9.0.0* | v9.3.0* | v9.11.0* | | | | +| v10.x | v10.0.0 | v10.0.0 | v10.0.0 | v10.16.0 | v10.17.0 | v10.20.0 | +| v11.x | v11.0.0 | v11.0.0 | v11.0.0 | v11.8.0 | | | +| v12.x | v12.0.0 | v12.0.0 | v12.0.0 | v12.0.0 | v12.11.0 | v12.17.0 | +| v13.x | v13.0.0 | v13.0.0 | v13.0.0 | v13.0.0 | v13.0.0 | | +| v14.x | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | \* Indicates that the N-API version was released as experimental +\*\* First version which matches version 1 in later releases. While v8.0.0 +included N-API as experimental, version 1 continued to evolve until +v8.6.0 and therefore the shape of the API in earlier versions is not +truly version 1 (in hindsight we should have called it version 0). +We recommend version 3 or later. + The N-APIs associated strictly with accessing ECMAScript features from native code can be found separately in `js_native_api.h` and `js_native_api_types.h`. The APIs defined in these headers are included in `node_api.h` and From c1abc8d3e5ff8385d2a7e42a812ed2b22f4966e7 Mon Sep 17 00:00:00 2001 From: Andrey Pechkurov Date: Thu, 30 Jul 2020 20:30:43 +0300 Subject: [PATCH 22/79] src: fix unused namespace member in node_util PR-URL: https://github.com/nodejs/node/pull/34565 Reviewed-By: Zeyu Yang Reviewed-By: Richard Lau Reviewed-By: James M Snell --- src/node_util.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/node_util.cc b/src/node_util.cc index f62c2922d5f3e9..eac09f8d44fcbd 100644 --- a/src/node_util.cc +++ b/src/node_util.cc @@ -20,7 +20,6 @@ using v8::Integer; using v8::Isolate; using v8::KeyCollectionMode; using v8::Local; -using v8::MaybeLocal; using v8::Object; using v8::ONLY_CONFIGURABLE; using v8::ONLY_ENUMERABLE; From 36fd3daae6fc8f1e8fa498b99920ef7bc842c4ff Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Thu, 30 Jul 2020 16:58:08 +0200 Subject: [PATCH 23/79] http: provide keep-alive timeout response header In http 1.1 persistent connection protocol there is a timing race where the client sends the request and then the server kills the connection (due to inactivity) before receiving the client's request. By providing a keep-alive header it is possible to provide the client a hint of when idle timeout would occur and avoid the race. Fixes: https://github.com/nodejs/node/issues/34560 PR-URL: https://github.com/nodejs/node/pull/34561 Reviewed-By: Anna Henningsen Reviewed-By: Matteo Collina Reviewed-By: Luigi Pinca Reviewed-By: Zeyu Yang Reviewed-By: Trivikram Kamat Reviewed-By: Pranshu Srivastava --- lib/_http_outgoing.js | 7 +++++ lib/_http_server.js | 1 + test/parallel/test-http-keep-alive-timeout.js | 28 +++++++++++++++++++ 3 files changed, 36 insertions(+) create mode 100644 test/parallel/test-http-keep-alive-timeout.js diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js index aba05590dc25c3..f1392b6335ccad 100644 --- a/lib/_http_outgoing.js +++ b/lib/_http_outgoing.js @@ -28,6 +28,7 @@ const { ObjectKeys, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, + MathFloor, Symbol, } = primordials; @@ -118,6 +119,8 @@ function OutgoingMessage() { this._header = null; this[kOutHeaders] = null; + this._keepAliveTimeout = 0; + this._onPendingData = noopPendingOutput; } ObjectSetPrototypeOf(OutgoingMessage.prototype, Stream.prototype); @@ -419,6 +422,10 @@ function _storeHeader(firstLine, headers) { (state.contLen || this.useChunkedEncodingByDefault || this.agent); if (shouldSendKeepAlive) { header += 'Connection: keep-alive\r\n'; + if (this._keepAliveTimeout) { + const timeoutSeconds = MathFloor(this._keepAliveTimeout) / 1000; + header += `Keep-Alive: timeout=${timeoutSeconds}\r\n`; + } } else { this._last = true; header += 'Connection: close\r\n'; diff --git a/lib/_http_server.js b/lib/_http_server.js index c34f8092ecb6ce..fa0c922a61093f 100644 --- a/lib/_http_server.js +++ b/lib/_http_server.js @@ -743,6 +743,7 @@ function parserOnIncoming(server, socket, state, req, keepAlive) { } const res = new server[kServerResponse](req); + res._keepAliveTimeout = server.keepAliveTimeout; res._onPendingData = updateOutgoingData.bind(undefined, socket, state); res.shouldKeepAlive = keepAlive; diff --git a/test/parallel/test-http-keep-alive-timeout.js b/test/parallel/test-http-keep-alive-timeout.js new file mode 100644 index 00000000000000..fccb267b8e9ee2 --- /dev/null +++ b/test/parallel/test-http-keep-alive-timeout.js @@ -0,0 +1,28 @@ +'use strict'; + +const common = require('../common'); +const http = require('http'); +const assert = require('assert'); + +const server = http.createServer(common.mustCall((req, res) => { + const body = 'hello world\n'; + + res.writeHead(200, { 'Content-Length': body.length }); + res.write(body); + res.end(); +})); +server.keepAliveTimeout = 12000; + +const agent = new http.Agent({ maxSockets: 1, keepAlive: true }); + +server.listen(0, common.mustCall(function() { + http.get({ + path: '/', port: this.address().port, agent: agent + }, common.mustCall((response) => { + response.resume(); + assert.strictEqual( + response.headers['keep-alive'], 'timeout=12'); + server.close(); + agent.destroy(); + })); +})); From d7eaf3a0274f37825d3936ee0044083c21859677 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 30 Jul 2020 10:33:33 -0700 Subject: [PATCH 24/79] doc: revise N-API versions matrix text Revise text for clarity, brevity, and conformance with our style guide. PR-URL: https://github.com/nodejs/node/pull/34566 Reviewed-By: Gus Caplan Reviewed-By: Michael Dawson Reviewed-By: Richard Lau Reviewed-By: James M Snell --- doc/api/n-api.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index d5f96d015105a7..676b08f37306b1 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -251,13 +251,11 @@ listed as supporting a later version. | v13.x | v13.0.0 | v13.0.0 | v13.0.0 | v13.0.0 | v13.0.0 | | | v14.x | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | v14.0.0 | -\* Indicates that the N-API version was released as experimental +\* N-API was experimental. -\*\* First version which matches version 1 in later releases. While v8.0.0 -included N-API as experimental, version 1 continued to evolve until -v8.6.0 and therefore the shape of the API in earlier versions is not -truly version 1 (in hindsight we should have called it version 0). -We recommend version 3 or later. +\*\* Node.js 8.0.0 included N-API as experimental. It was released as N-API +version 1 but continued to evolve until Node.js 8.6.0. The API is different in +versions prior to Node.js 8.6.0. We recommend N-API version 3 or later. The N-APIs associated strictly with accessing ECMAScript features from native code can be found separately in `js_native_api.h` and `js_native_api_types.h`. From 7322e58d118861801530153b2c4dbfc5e83cfac7 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Fri, 31 Jul 2020 14:42:39 +0200 Subject: [PATCH 25/79] http: reset headers timeout on headers complete headers timeout should not occur *after* headers have been received. Fixes: https://github.com/nodejs/node/issues/34576 PR-URL: https://github.com/nodejs/node/pull/34578 Reviewed-By: Anna Henningsen Reviewed-By: Fedor Indutny Reviewed-By: Luigi Pinca Reviewed-By: James M Snell Reviewed-By: Pranshu Srivastava --- src/node_http_parser.cc | 1 + .../test-http-parser-timeout-reset.js | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 test/parallel/test-http-parser-timeout-reset.js diff --git a/src/node_http_parser.cc b/src/node_http_parser.cc index c7a3df8d067af4..b409d007307877 100644 --- a/src/node_http_parser.cc +++ b/src/node_http_parser.cc @@ -280,6 +280,7 @@ class Parser : public AsyncWrap, public StreamListener { int on_headers_complete() { header_nread_ = 0; + header_parsing_start_time_ = 0; // Arguments for the on-headers-complete javascript callback. This // list needs to be kept in sync with the actual argument list for diff --git a/test/parallel/test-http-parser-timeout-reset.js b/test/parallel/test-http-parser-timeout-reset.js new file mode 100644 index 00000000000000..c9daa7c2124a73 --- /dev/null +++ b/test/parallel/test-http-parser-timeout-reset.js @@ -0,0 +1,46 @@ +'use strict'; +const common = require('../common'); + +const net = require('net'); +const { HTTPParser } = process.binding('http_parser'); + +const server = net.createServer((socket) => { + socket.write('HTTP/1.1 200 OK\r\n'); + socket.write('Transfer-Encoding: chunked\r\n\r\n'); + setTimeout(() => { + socket.write('1\r\n'); + socket.write('\n\r\n'); + setTimeout(() => { + socket.write('1\r\n'); + socket.write('\n\r\n'); + setImmediate(() => { + socket.destroy(); + server.close(); + }); + }, 500); + }, 500); +}).listen(0, () => { + const socket = net.connect(server.address().port); + const parser = new HTTPParser(HTTPParser.RESPONSE, false); + parser.initialize( + HTTPParser.RESPONSE, + {}, + 0, + false, + 1e3 + ); + + parser[HTTPParser.kOnTimeout] = common.mustNotCall(); + + parser[HTTPParser.kOnHeaders] = common.mustNotCall(); + + parser[HTTPParser.kOnExecute] = common.mustCall(3); + + parser[HTTPParser.kOnHeadersComplete] = common.mustCall(); + + parser[HTTPParser.kOnBody] = common.mustCall(2); + + parser[HTTPParser.kOnMessageComplete] = common.mustNotCall(); + + parser.consume(socket._handle); +}); From 10dd7a0edaf5a8c6c50dd6355808fb76d19761f4 Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Sun, 2 Aug 2020 12:19:20 -0400 Subject: [PATCH 26/79] doc: add DerekNonGeneric to collaborators Fixes: https://github.com/nodejs/node/issues/34369 PR-URL: https://github.com/nodejs/node/pull/34602 Reviewed-By: Rich Trott Reviewed-By: Anna Henningsen Reviewed-By: Gireesh Punathil --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 4e972c8d005d7f..1b74520231af63 100644 --- a/README.md +++ b/README.md @@ -283,6 +283,8 @@ For information about the governance of the Node.js project, see **Danielle Adams** <adamzdanielle@gmail.com> (she/her) * [davisjam](https://github.com/davisjam) - **Jamie Davis** <davisjam@vt.edu> (he/him) +* [DerekNonGeneric](https://github.com/DerekNonGeneric) - +**Derek Lewis** <DerekNonGeneric@inf.is> (he/him) * [devnexen](https://github.com/devnexen) - **David Carlier** <devnexen@gmail.com> * [devsnek](https://github.com/devsnek) - From 0a9389bb1adfe7ca0f5084c945d62e843d8b1afd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9e=20Kooi?= Date: Fri, 31 Jul 2020 13:54:24 +0200 Subject: [PATCH 27/79] doc: mention null special-case for `napi_typeof` The documentation said `napi_typeof` is similar to the `typeof` operator, but the `typeof null` detects `'object'` while `napi_typeof(a_null_value)` detects `napi_null`. PR-URL: https://github.com/nodejs/node/pull/34577 Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Gabriel Schulhof Reviewed-By: Luigi Pinca Reviewed-By: David Carlier --- doc/api/n-api.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 676b08f37306b1..bc02572bf07ed8 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -3165,7 +3165,12 @@ Returns `napi_ok` if the API succeeded. This API represents behavior similar to invoking the `typeof` Operator on the object as defined in [Section 12.5.5][] of the ECMAScript Language -Specification. However, it has support for detecting an External value. +Specification. However, there are some differences: + +1. It has support for detecting an External value. +2. It detects `null` as a separate type, while ECMAScript `typeof` would detect + `object`. + If `value` has a type that is invalid, an error is returned. ### napi_instanceof From 9af62641c6e60d270aa2d6524ed3015fb219b336 Mon Sep 17 00:00:00 2001 From: Gerhard Stoebich <18708370+Flarna@users.noreply.github.com> Date: Mon, 13 Jul 2020 20:31:00 +0200 Subject: [PATCH 28/79] async_hooks: execute destroy hooks earlier Use a microtask to call destroy hooks in case there are a lot queued as immediate may be scheduled late in case of long running promise chains. Queuing a mircrotasks in GC context is not allowed therefore an interrupt is triggered to do this in JS context as fast as possible. fixes: https://github.com/nodejs/node/issues/34328 refs: https://github.com/nodejs/node/issues/33896 PR-URL: https://github.com/nodejs/node/pull/34342 Fixes: https://github.com/nodejs/node/issues/34328 Refs: https://github.com/nodejs/node/issues/33896 Reviewed-By: Gus Caplan Reviewed-By: Anna Henningsen Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell --- src/async_wrap.cc | 12 +++ test/async-hooks/test-destroy-not-blocked.js | 97 ++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 test/async-hooks/test-destroy-not-blocked.js diff --git a/src/async_wrap.cc b/src/async_wrap.cc index d206c33562470e..7d8cc4d7393a16 100644 --- a/src/async_wrap.cc +++ b/src/async_wrap.cc @@ -836,6 +836,18 @@ void AsyncWrap::EmitDestroy(Environment* env, double async_id) { env->SetImmediate(&DestroyAsyncIdsCallback, CallbackFlags::kUnrefed); } + // If the list gets very large empty it faster using a Microtask. + // Microtasks can't be added in GC context therefore we use an + // interrupt to get this Microtask scheduled as fast as possible. + if (env->destroy_async_id_list()->size() == 16384) { + env->RequestInterrupt([](Environment* env) { + env->isolate()->EnqueueMicrotask( + [](void* arg) { + DestroyAsyncIdsCallback(static_cast(arg)); + }, env); + }); + } + env->destroy_async_id_list()->push_back(async_id); } diff --git a/test/async-hooks/test-destroy-not-blocked.js b/test/async-hooks/test-destroy-not-blocked.js new file mode 100644 index 00000000000000..aa467f30143806 --- /dev/null +++ b/test/async-hooks/test-destroy-not-blocked.js @@ -0,0 +1,97 @@ +'use strict'; +// Flags: --expose_gc + +const common = require('../common'); +const assert = require('assert'); +const tick = require('../common/tick'); + +const { createHook, AsyncResource } = require('async_hooks'); + +// Test priority of destroy hook relative to nextTick,... and +// verify a microtask is scheduled in case a lot items are queued + +const resType = 'MyResource'; +let activeId = -1; +createHook({ + init(id, type) { + if (type === resType) { + assert.strictEqual(activeId, -1); + activeId = id; + } + }, + destroy(id) { + if (activeId === id) { + activeId = -1; + } + } +}).enable(); + +function testNextTick() { + assert.strictEqual(activeId, -1); + const res = new AsyncResource(resType); + assert.strictEqual(activeId, res.asyncId()); + res.emitDestroy(); + // nextTick has higher prio than emit destroy + process.nextTick(common.mustCall(() => + assert.strictEqual(activeId, res.asyncId())) + ); +} + +function testQueueMicrotask() { + assert.strictEqual(activeId, -1); + const res = new AsyncResource(resType); + assert.strictEqual(activeId, res.asyncId()); + res.emitDestroy(); + // queueMicrotask has higher prio than emit destroy + queueMicrotask(common.mustCall(() => + assert.strictEqual(activeId, res.asyncId())) + ); +} + +function testImmediate() { + assert.strictEqual(activeId, -1); + const res = new AsyncResource(resType); + assert.strictEqual(activeId, res.asyncId()); + res.emitDestroy(); + setImmediate(common.mustCall(() => + assert.strictEqual(activeId, -1)) + ); +} + +function testPromise() { + assert.strictEqual(activeId, -1); + const res = new AsyncResource(resType); + assert.strictEqual(activeId, res.asyncId()); + res.emitDestroy(); + // Promise has higher prio than emit destroy + Promise.resolve().then(common.mustCall(() => + assert.strictEqual(activeId, res.asyncId())) + ); +} + +async function testAwait() { + assert.strictEqual(activeId, -1); + const res = new AsyncResource(resType); + assert.strictEqual(activeId, res.asyncId()); + res.emitDestroy(); + + for (let i = 0; i < 5000; i++) { + await Promise.resolve(); + } + global.gc(); + await Promise.resolve(); + // Limit to trigger a microtask not yet reached + assert.strictEqual(activeId, res.asyncId()); + for (let i = 0; i < 5000; i++) { + await Promise.resolve(); + } + global.gc(); + await Promise.resolve(); + assert.strictEqual(activeId, -1); +} + +testNextTick(); +tick(2, testQueueMicrotask); +tick(4, testImmediate); +tick(6, testPromise); +tick(8, () => testAwait().then(common.mustCall())); From 7c4e1db1b501b478a2c4273fcfd7f1f99137a115 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 31 Jul 2020 02:32:33 +0200 Subject: [PATCH 29/79] async_hooks: fix resource stack for deep stacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 460c81dc0e0 introduced a bug where the execution resource was not stored properly if we needed to call into C++ to extend the stack size. Fix that bug by always storing the resource. Refs: https://github.com/nodejs/node/pull/34319 Fixes: https://github.com/nodejs/node/issues/34556 PR-URL: https://github.com/nodejs/node/pull/34573 Reviewed-By: Andrey Pechkurov Reviewed-By: Benjamin Gruenbaum Reviewed-By: Gerhard Stöbich Reviewed-By: Gus Caplan --- lib/internal/async_hooks.js | 2 +- .../test-async-local-storage-deep-stack.js | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-async-local-storage-deep-stack.js diff --git a/lib/internal/async_hooks.js b/lib/internal/async_hooks.js index f4d4f1da49c4ca..9463d1d3348e67 100644 --- a/lib/internal/async_hooks.js +++ b/lib/internal/async_hooks.js @@ -499,11 +499,11 @@ function hasAsyncIdStack() { // This is the equivalent of the native push_async_ids() call. function pushAsyncContext(asyncId, triggerAsyncId, resource) { const offset = async_hook_fields[kStackLength]; + execution_async_resources[offset] = resource; if (offset * 2 >= async_wrap.async_ids_stack.length) return pushAsyncContext_(asyncId, triggerAsyncId); async_wrap.async_ids_stack[offset * 2] = async_id_fields[kExecutionAsyncId]; async_wrap.async_ids_stack[offset * 2 + 1] = async_id_fields[kTriggerAsyncId]; - execution_async_resources[offset] = resource; async_hook_fields[kStackLength]++; async_id_fields[kExecutionAsyncId] = asyncId; async_id_fields[kTriggerAsyncId] = triggerAsyncId; diff --git a/test/parallel/test-async-local-storage-deep-stack.js b/test/parallel/test-async-local-storage-deep-stack.js new file mode 100644 index 00000000000000..b5e1048d94a4ed --- /dev/null +++ b/test/parallel/test-async-local-storage-deep-stack.js @@ -0,0 +1,15 @@ +'use strict'; +const common = require('../common'); +const { AsyncLocalStorage } = require('async_hooks'); + +// Regression test for: https://github.com/nodejs/node/issues/34556 + +const als = new AsyncLocalStorage(); + +const done = common.mustCall(); + +function run(count) { + if (count !== 0) return als.run({}, run, --count); + done(); +} +run(1000); From 283f5c3a1454413702d9b5ccc45c1b9b20a52ec5 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Mon, 3 Aug 2020 12:52:08 +0200 Subject: [PATCH 30/79] test: fix flaky http-parser-timeout-reset Refs: https://github.com/nodejs/node/pull/34578#issuecomment-667941698 PR-URL: https://github.com/nodejs/node/pull/34609 Reviewed-By: Richard Lau Reviewed-By: Myles Borins --- test/parallel/test-http-parser-timeout-reset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/parallel/test-http-parser-timeout-reset.js b/test/parallel/test-http-parser-timeout-reset.js index c9daa7c2124a73..1ba72d865f73fb 100644 --- a/test/parallel/test-http-parser-timeout-reset.js +++ b/test/parallel/test-http-parser-timeout-reset.js @@ -34,7 +34,7 @@ const server = net.createServer((socket) => { parser[HTTPParser.kOnHeaders] = common.mustNotCall(); - parser[HTTPParser.kOnExecute] = common.mustCall(3); + parser[HTTPParser.kOnExecute] = common.mustCallAtLeast(3); parser[HTTPParser.kOnHeadersComplete] = common.mustCall(); From 1b0d3b2c5289d139ce786b3d79485ede56f5395d Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 27 Jul 2020 20:08:38 +0200 Subject: [PATCH 31/79] doc: document the connection event for HTTP2 & TLS servers PR-URL: https://github.com/nodejs/node/pull/34531 Reviewed-By: Matteo Collina Reviewed-By: Luigi Pinca --- doc/api/http2.md | 28 ++++++++++++++++++++++++++++ doc/api/tls.md | 15 +++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/doc/api/http2.md b/doc/api/http2.md index 48aa027992291e..6b7f002cba0a49 100644 --- a/doc/api/http2.md +++ b/doc/api/http2.md @@ -1727,6 +1727,20 @@ the request body. When this event is emitted and handled, the [`'request'`][] event will not be emitted. +### Event: `'connection'` + + +* `socket` {stream.Duplex} + +This event is emitted when a new TCP stream is established. `socket` is +typically an object of type [`net.Socket`][]. Usually users will not want to +access this event. + +This event can also be explicitly emitted by users to inject connections +into the HTTP server. In that case, any [`Duplex`][] stream can be passed. + #### Event: `'request'` + +* `socket` {stream.Duplex} + +This event is emitted when a new TCP stream is established, before the TLS +handshake begins. `socket` is typically an object of type [`net.Socket`][]. +Usually users will not want to access this event. + +This event can also be explicitly emitted by users to inject connections +into the HTTP server. In that case, any [`Duplex`][] stream can be passed. + #### Event: `'request'` + +* `socket` {stream.Duplex} + +This event is emitted when a new TCP stream is established, before the TLS +handshake begins. `socket` is typically an object of type [`net.Socket`][]. +Usually users will not want to access this event. + +This event can also be explicitly emitted by users to inject connections +into the TLS server. In that case, any [`Duplex`][] stream can be passed. + ### Event: `'keylog'` ## Technology Sponsors diff --git a/tools/node_modules/eslint/lib/cli-engine/formatters/checkstyle.js b/tools/node_modules/eslint/lib/cli-engine/formatters/checkstyle.js index ba4d1b5b3ec532..f19b6fc0957e5d 100644 --- a/tools/node_modules/eslint/lib/cli-engine/formatters/checkstyle.js +++ b/tools/node_modules/eslint/lib/cli-engine/formatters/checkstyle.js @@ -42,8 +42,8 @@ module.exports = function(results) { messages.forEach(message => { output += [ - `` diff --git a/tools/node_modules/eslint/lib/rule-tester/rule-tester.js b/tools/node_modules/eslint/lib/rule-tester/rule-tester.js index 77df1def893ccc..d1fcbca5ba0622 100644 --- a/tools/node_modules/eslint/lib/rule-tester/rule-tester.js +++ b/tools/node_modules/eslint/lib/rule-tester/rule-tester.js @@ -852,6 +852,16 @@ class RuleTester { ); } + // Rules that produce fixes must have `meta.fixable` property. + if (result.output !== item.code) { + assert.ok( + hasOwnProperty(rule, "meta"), + "Fixable rules should export a `meta.fixable` property." + ); + + // Linter throws if a rule that produced a fix has `meta` but doesn't have `meta.fixable`. + } + assertASTDidntChange(result.beforeAST, result.afterAST); } diff --git a/tools/node_modules/eslint/lib/rules/no-duplicate-case.js b/tools/node_modules/eslint/lib/rules/no-duplicate-case.js index c8a0fa9da3c025..e2d9665e7f564d 100644 --- a/tools/node_modules/eslint/lib/rules/no-duplicate-case.js +++ b/tools/node_modules/eslint/lib/rules/no-duplicate-case.js @@ -6,6 +6,12 @@ "use strict"; +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const astUtils = require("./utils/ast-utils"); + //------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------ @@ -31,18 +37,31 @@ module.exports = { create(context) { const sourceCode = context.getSourceCode(); + /** + * Determines whether the two given nodes are considered to be equal. + * @param {ASTNode} a First node. + * @param {ASTNode} b Second node. + * @returns {boolean} `true` if the nodes are considered to be equal. + */ + function equal(a, b) { + if (a.type !== b.type) { + return false; + } + + return astUtils.equalTokens(a, b, sourceCode); + } return { SwitchStatement(node) { - const previousKeys = new Set(); + const previousTests = []; for (const switchCase of node.cases) { if (switchCase.test) { - const key = sourceCode.getText(switchCase.test); + const test = switchCase.test; - if (previousKeys.has(key)) { + if (previousTests.some(previousTest => equal(previousTest, test))) { context.report({ node: switchCase, messageId: "unexpected" }); } else { - previousKeys.add(key); + previousTests.push(test); } } } diff --git a/tools/node_modules/eslint/messages/extend-config-missing.txt b/tools/node_modules/eslint/messages/extend-config-missing.txt index f7c5f71ebe3256..4defd7ac4d159d 100644 --- a/tools/node_modules/eslint/messages/extend-config-missing.txt +++ b/tools/node_modules/eslint/messages/extend-config-missing.txt @@ -2,4 +2,4 @@ ESLint couldn't find the config "<%- configName %>" to extend from. Please check The config "<%- configName %>" was referenced from the config file in "<%- importerName %>". -If you still have problems, please stop by https://eslint.org/chat to chat with the team. +If you still have problems, please stop by https://eslint.org/chat/help to chat with the team. diff --git a/tools/node_modules/eslint/messages/no-config-found.txt b/tools/node_modules/eslint/messages/no-config-found.txt index f1f7beb63b19a0..b46a7e5a7a6f3f 100644 --- a/tools/node_modules/eslint/messages/no-config-found.txt +++ b/tools/node_modules/eslint/messages/no-config-found.txt @@ -4,4 +4,4 @@ ESLint couldn't find a configuration file. To set up a configuration file for th ESLint looked for configuration files in <%= directoryPath %> and its ancestors. If it found none, it then looked in your home directory. -If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://eslint.org/chat +If you think you already have a configuration file or if you need more help, please stop by the ESLint chat room: https://eslint.org/chat/help diff --git a/tools/node_modules/eslint/messages/plugin-conflict.txt b/tools/node_modules/eslint/messages/plugin-conflict.txt index f8b60631c58ea1..3ab4b340ef2dab 100644 --- a/tools/node_modules/eslint/messages/plugin-conflict.txt +++ b/tools/node_modules/eslint/messages/plugin-conflict.txt @@ -4,4 +4,4 @@ ESLint couldn't determine the plugin "<%- pluginId %>" uniquely. Please remove the "plugins" setting from either config or remove either plugin installation. -If you still can't figure out the problem, please stop by https://eslint.org/chat to chat with the team. +If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. diff --git a/tools/node_modules/eslint/messages/plugin-missing.txt b/tools/node_modules/eslint/messages/plugin-missing.txt index 3d376733085667..aa25f59ac440ba 100644 --- a/tools/node_modules/eslint/messages/plugin-missing.txt +++ b/tools/node_modules/eslint/messages/plugin-missing.txt @@ -8,4 +8,4 @@ It's likely that the plugin isn't installed correctly. Try reinstalling by runni The plugin "<%- pluginName %>" was referenced from the config file in "<%- importerName %>". -If you still can't figure out the problem, please stop by https://eslint.org/chat to chat with the team. +If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. diff --git a/tools/node_modules/eslint/messages/whitespace-found.txt b/tools/node_modules/eslint/messages/whitespace-found.txt index 7d72149a8fd4fb..3eed1af58665a3 100644 --- a/tools/node_modules/eslint/messages/whitespace-found.txt +++ b/tools/node_modules/eslint/messages/whitespace-found.txt @@ -1,3 +1,3 @@ ESLint couldn't find the plugin "<%- pluginName %>". because there is whitespace in the name. Please check your configuration and remove all whitespace from the plugin name. -If you still can't figure out the problem, please stop by https://eslint.org/chat to chat with the team. +If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team. diff --git a/tools/node_modules/eslint/package.json b/tools/node_modules/eslint/package.json index 193a95c950bdb7..a0b031f6e9baf1 100644 --- a/tools/node_modules/eslint/package.json +++ b/tools/node_modules/eslint/package.json @@ -153,5 +153,5 @@ "test:cli": "mocha", "webpack": "node Makefile.js webpack" }, - "version": "7.5.0" + "version": "7.6.0" } \ No newline at end of file From ae64ec46118a3cae02a25ff5f4104d09eb7143d3 Mon Sep 17 00:00:00 2001 From: Bradley Farias Date: Tue, 14 Jul 2020 16:31:29 -0500 Subject: [PATCH 36/79] repl: give repl entries unique names This is a workaround for the REPL for a problem when multiple of the entries have the same source text Fixes: https://github.com/nodejs/node/issues/1337 Refs: https://bugs.chromium.org/p/v8/issues/detail?id=10284 PR-URL: https://github.com/nodejs/node/pull/34372 Reviewed-By: Ruben Bridgewater Reviewed-By: Anto Aravinth --- lib/repl.js | 14 +++++++++---- test/parallel/test-repl-dynamic-import.js | 20 +++++++++++++++++++ .../parallel/test-repl-pretty-custom-stack.js | 12 +++++------ test/parallel/test-repl-pretty-stack.js | 14 ++++++------- 4 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 test/parallel/test-repl-dynamic-import.js diff --git a/lib/repl.js b/lib/repl.js index 26376a43c56d66..760a71d80ae93e 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -128,6 +128,12 @@ const { } = internalBinding('contextify'); const history = require('internal/repl/history'); +let nextREPLResourceNumber = 1; +// This prevents v8 code cache from getting confused and using a different +// cache from a resource of the same name +function getREPLResourceName() { + return `REPL${nextREPLResourceNumber++}`; +} // Lazy-loaded. let processTopLevelAwait; @@ -578,10 +584,10 @@ function REPLServer(prompt, if (e.name === 'SyntaxError') { // Remove stack trace. e.stack = e.stack - .replace(/^repl:\d+\r?\n/, '') + .replace(/^REPL\d+:\d+\r?\n/, '') .replace(/^\s+at\s.*\n?/gm, ''); } else if (self.replMode === module.exports.REPL_MODE_STRICT) { - e.stack = e.stack.replace(/(\s+at\s+repl:)(\d+)/, + e.stack = e.stack.replace(/(\s+at\s+REPL\d+:)(\d+)/, (_, pre, line) => pre + (line - 1)); } } @@ -791,7 +797,7 @@ function REPLServer(prompt, const evalCmd = self[kBufferedCommandSymbol] + cmd + '\n'; debug('eval %j', evalCmd); - self.eval(evalCmd, self.context, 'repl', finish); + self.eval(evalCmd, self.context, getREPLResourceName(), finish); function finish(e, ret) { debug('finish', e, ret); @@ -1277,7 +1283,7 @@ function complete(line, callback) { const memberGroups = []; const evalExpr = `try { ${expr} } catch {}`; - this.eval(evalExpr, this.context, 'repl', (e, obj) => { + this.eval(evalExpr, this.context, getREPLResourceName(), (e, obj) => { try { let p; if ((typeof obj === 'object' && obj !== null) || diff --git a/test/parallel/test-repl-dynamic-import.js b/test/parallel/test-repl-dynamic-import.js new file mode 100644 index 00000000000000..1f7a01575aa89b --- /dev/null +++ b/test/parallel/test-repl-dynamic-import.js @@ -0,0 +1,20 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const child_process = require('child_process'); +const child = child_process.spawn(process.execPath, [ + '--interactive', + '--expose-gc' +], { + stdio: 'pipe' +}); +child.stdin.write('\nimport("fs");\n_.then(gc);\n'); +// Wait for concurrent GC to finish +setTimeout(() => { + child.stdin.write('\nimport("fs");\n'); + child.stdin.write('\nprocess.exit(0);\n'); +}, common.platformTimeout(50)); +child.on('exit', (code, signal) => { + assert.strictEqual(code, 0); + assert.strictEqual(signal, null); +}); diff --git a/test/parallel/test-repl-pretty-custom-stack.js b/test/parallel/test-repl-pretty-custom-stack.js index 8f633a4d4808c5..d04a394a2e249e 100644 --- a/test/parallel/test-repl-pretty-custom-stack.js +++ b/test/parallel/test-repl-pretty-custom-stack.js @@ -5,7 +5,7 @@ const fixtures = require('../common/fixtures'); const assert = require('assert'); const repl = require('repl'); -const stackRegExp = /repl:[0-9]+:[0-9]+/g; +const stackRegExp = /(REPL\d+):[0-9]+:[0-9]+/g; function run({ command, expected }) { let accum = ''; @@ -25,8 +25,8 @@ function run({ command, expected }) { r.write(`${command}\n`); assert.strictEqual( - accum.replace(stackRegExp, 'repl:*:*'), - expected.replace(stackRegExp, 'repl:*:*') + accum.replace(stackRegExp, '$1:*:*'), + expected.replace(stackRegExp, '$1:*:*') ); r.close(); } @@ -48,8 +48,8 @@ const tests = [ { // test .load for a file that throws command: `.load ${fixtures.path('repl-pretty-stack.js')}`, - expected: 'Uncaught Error: Whoops!--->\nrepl:*:*--->\nd (repl:*:*)' + - '--->\nc (repl:*:*)--->\nb (repl:*:*)--->\na (repl:*:*)\n' + expected: 'Uncaught Error: Whoops!--->\nREPL1:*:*--->\nd (REPL1:*:*)' + + '--->\nc (REPL1:*:*)--->\nb (REPL1:*:*)--->\na (REPL1:*:*)\n' }, { command: 'let x y;', @@ -67,7 +67,7 @@ const tests = [ // test anonymous IIFE { command: '(function() { throw new Error(\'Whoops!\'); })()', - expected: 'Uncaught Error: Whoops!--->\nrepl:*:*\n' + expected: 'Uncaught Error: Whoops!--->\nREPL5:*:*\n' } ]; diff --git a/test/parallel/test-repl-pretty-stack.js b/test/parallel/test-repl-pretty-stack.js index 456e866b7b20f9..8ab3fef2aaa033 100644 --- a/test/parallel/test-repl-pretty-stack.js +++ b/test/parallel/test-repl-pretty-stack.js @@ -5,7 +5,7 @@ const fixtures = require('../common/fixtures'); const assert = require('assert'); const repl = require('repl'); -const stackRegExp = /(at .*repl:)[0-9]+:[0-9]+/g; +const stackRegExp = /(at .*REPL\d+:)[0-9]+:[0-9]+/g; function run({ command, expected, ...extraREPLOptions }, i) { let accum = ''; @@ -37,9 +37,9 @@ const tests = [ { // Test .load for a file that throws. command: `.load ${fixtures.path('repl-pretty-stack.js')}`, - expected: 'Uncaught Error: Whoops!\n at repl:*:*\n' + - ' at d (repl:*:*)\n at c (repl:*:*)\n' + - ' at b (repl:*:*)\n at a (repl:*:*)\n' + expected: 'Uncaught Error: Whoops!\n at REPL1:*:*\n' + + ' at d (REPL1:*:*)\n at c (REPL1:*:*)\n' + + ' at b (REPL1:*:*)\n at a (REPL1:*:*)\n' }, { command: 'let x y;', @@ -53,12 +53,12 @@ const tests = [ { command: '(() => { const err = Error(\'Whoops!\'); ' + 'err.foo = \'bar\'; throw err; })()', - expected: "Uncaught Error: Whoops!\n at repl:*:* {\n foo: 'bar'\n}\n", + expected: "Uncaught Error: Whoops!\n at REPL4:*:* {\n foo: 'bar'\n}\n", }, { command: '(() => { const err = Error(\'Whoops!\'); ' + 'err.foo = \'bar\'; throw err; })()', - expected: 'Uncaught Error: Whoops!\n at repl:*:* {\n foo: ' + + expected: 'Uncaught Error: Whoops!\n at REPL5:*:* {\n foo: ' + "\u001b[32m'bar'\u001b[39m\n}\n", useColors: true }, @@ -69,7 +69,7 @@ const tests = [ // Test anonymous IIFE. { command: '(function() { throw new Error(\'Whoops!\'); })()', - expected: 'Uncaught Error: Whoops!\n at repl:*:*\n' + expected: 'Uncaught Error: Whoops!\n at REPL7:*:*\n' } ]; From d6b0a40662e609e71025cdf0abd005de054010f7 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Mon, 27 Jul 2020 18:19:33 +0200 Subject: [PATCH 37/79] test: replace flaky pummel regression tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These tests were written a long time ago, and use the allocation of large amounts of unused memory as a way to detect use-after-free problems with Buffers. As a result, the tests are resource-intensive and may crash because of that. Replace them with a more modern test. We don’t explicitly try to *detect* use-after-free conditions, and instead rely on e.g. ASAN (or the process just crashing hard) to do that for us. Fixes: https://github.com/nodejs/node/issues/34527 PR-URL: https://github.com/nodejs/node/pull/34530 Reviewed-By: Rich Trott Reviewed-By: Andrey Pechkurov Reviewed-By: Jiawen Geng --- test/parallel/test-fs-write-reuse-callback.js | 39 +++++++ test/pummel/test-regress-GH-814.js | 90 --------------- test/pummel/test-regress-GH-814_2.js | 105 ------------------ 3 files changed, 39 insertions(+), 195 deletions(-) create mode 100644 test/parallel/test-fs-write-reuse-callback.js delete mode 100644 test/pummel/test-regress-GH-814.js delete mode 100644 test/pummel/test-regress-GH-814_2.js diff --git a/test/parallel/test-fs-write-reuse-callback.js b/test/parallel/test-fs-write-reuse-callback.js new file mode 100644 index 00000000000000..13a33a7545263b --- /dev/null +++ b/test/parallel/test-fs-write-reuse-callback.js @@ -0,0 +1,39 @@ +// Flags: --expose-gc +'use strict'; +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); +const assert = require('assert'); +const path = require('path'); + +// Regression test for https://github.com/nodejs/node-v0.x-archive/issues/814: +// Make sure that Buffers passed to fs.write() are not garbage-collected +// even when the callback is being reused. + +const fs = require('fs'); + +tmpdir.refresh(); +const filename = path.join(tmpdir.path, 'test.txt'); +const fd = fs.openSync(filename, 'w'); + +const size = 16 * 1024; +const writes = 1000; +let done = 0; + +const ondone = common.mustCall((err) => { + assert.ifError(err); + if (++done < writes) { + if (done % 25 === 0) global.gc(); + setImmediate(write); + } else { + assert.strictEqual( + fs.readFileSync(filename, 'utf8'), + 'x'.repeat(writes * size)); + fs.closeSync(fd); + } +}, writes); + +write(); +function write() { + const buf = Buffer.alloc(size, 'x'); + fs.write(fd, buf, 0, buf.size, -1, ondone); +} diff --git a/test/pummel/test-regress-GH-814.js b/test/pummel/test-regress-GH-814.js deleted file mode 100644 index 323163225738b4..00000000000000 --- a/test/pummel/test-regress-GH-814.js +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// Refs: https://github.com/nodejs/node-v0.x-archive/issues/814 - -'use strict'; -// Flags: --expose_gc - -require('../common'); -const assert = require('assert'); - -const tmpdir = require('../common/tmpdir'); - -function newBuffer(size, value) { - const buffer = Buffer.allocUnsafe(size); - while (size--) { - buffer[size] = value; - } - buffer[buffer.length - 1] = 0x0a; - return buffer; -} - -const fs = require('fs'); - -tmpdir.refresh(); -const testFileName = require('path').join(tmpdir.path, 'GH-814_testFile.txt'); -const testFileFD = fs.openSync(testFileName, 'w'); -console.log(testFileName); - - -const kBufSize = 128 * 1024; -let PASS = true; -const neverWrittenBuffer = newBuffer(kBufSize, 0x2e); // 0x2e === '.' -const bufPool = []; - - -const tail = require('child_process').spawn('tail', ['-f', testFileName]); -tail.stdout.on('data', tailCB); - -function tailCB(data) { - PASS = !data.toString().includes('.'); -} - - -const timeToQuit = Date.now() + 8e3; // Test during no more than this seconds. -(function main() { - - if (PASS) { - fs.write(testFileFD, newBuffer(kBufSize, 0x61), 0, kBufSize, -1, cb); - global.gc(); - const nuBuf = Buffer.allocUnsafe(kBufSize); - neverWrittenBuffer.copy(nuBuf); - if (bufPool.push(nuBuf) > 100) { - bufPool.length = 0; - } - } else { - throw new Error("Buffer GC'ed test -> FAIL"); - } - - if (Date.now() < timeToQuit) { - process.nextTick(main); - } else { - tail.kill(); - console.log("Buffer GC'ed test -> PASS (OK)"); - } - -})(); - - -function cb(err, written) { - assert.ifError(err); -} diff --git a/test/pummel/test-regress-GH-814_2.js b/test/pummel/test-regress-GH-814_2.js deleted file mode 100644 index 6806a7fc45143c..00000000000000 --- a/test/pummel/test-regress-GH-814_2.js +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// Refs: https://github.com/nodejs/node-v0.x-archive/issues/814 - -'use strict'; -// Flags: --expose_gc - -require('../common'); -const assert = require('assert'); - -const fs = require('fs'); -const tmpdir = require('../common/tmpdir'); - -tmpdir.refresh(); -const testFileName = require('path').join(tmpdir.path, 'GH-814_test.txt'); -const testFD = fs.openSync(testFileName, 'w'); -console.error(`${testFileName}\n`); - - -const tailProc = require('child_process').spawn('tail', ['-f', testFileName]); -tailProc.stdout.on('data', tailCB); - -function tailCB(data) { - PASS = !data.toString().includes('.'); - - if (!PASS) { - console.error('[FAIL]\n DATA -> '); - console.error(data); - console.error('\n'); - throw new Error('Buffers GC test -> FAIL'); - } -} - - -let PASS = true; -const bufPool = []; -const kBufSize = 16 * 1024 * 1024; -const neverWrittenBuffer = newBuffer(kBufSize, 0x2e); // 0x2e === '.' - -const timeToQuit = Date.now() + 5e3; // Test should last no more than this. -writer(); - -function writer() { - - if (PASS) { - if (Date.now() > timeToQuit) { - setTimeout(function() { - process.kill(tailProc.pid); - console.error('\nBuffers GC test -> PASS (OK)\n'); - }, 555); - } else { - fs.write(testFD, newBuffer(kBufSize, 0x61), 0, kBufSize, -1, writerCB); - global.gc(); - global.gc(); - global.gc(); - global.gc(); - global.gc(); - global.gc(); - const nuBuf = Buffer.allocUnsafe(kBufSize); - neverWrittenBuffer.copy(nuBuf); - if (bufPool.push(nuBuf) > 100) { - bufPool.length = 0; - } - process.nextTick(writer); - } - } - -} - -function writerCB(err, written) { - assert.ifError(err); -} - - -// ******************* UTILITIES - - -function newBuffer(size, value) { - const buffer = Buffer.allocUnsafe(size); - while (size--) { - buffer[size] = value; - } - buffer[buffer.length - 1] = 0x0d; - buffer[buffer.length - 1] = 0x0a; - return buffer; -} From d972c54e9278cad54365e0af882293552ba7e941 Mon Sep 17 00:00:00 2001 From: Corey Butler Date: Wed, 29 Jul 2020 17:23:51 -0500 Subject: [PATCH 38/79] doc: clarify process.title inconsistencies Many users assume the act of assigning a value to `process.title` will update the name of their application in apps like macOS Activity Monitor or Windows Services Manager. This has worked in the past, but fails in some versions of Node.js. Ultimately developers are left confused, especially when it works in one version of Node.js and not another. Given the recurring nature and complexity of the underlying problem, it does not seem like a resolvable problem. This note clarifies the source of the problem, sets developer expectations. Refs: https://github.com/nodejs/node/issues/28945 PR-URL: https://github.com/nodejs/node/pull/34557 Fixes: https://github.com/nodejs/node/issues/34280 Reviewed-By: Ben Noordhuis Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca Reviewed-By: Rich Trott --- doc/api/process.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/api/process.md b/doc/api/process.md index a07b05d8b262c7..668e9ac0b1d2e2 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -2401,6 +2401,12 @@ allowed for longer process title strings by also overwriting the `environ` memory but that was potentially insecure and confusing in some (rather obscure) cases. +Assigning a value to `process.title` _may_ not reflect an accurate +(or any) label within the process manager application of the underlying +operating system (i.e. macOS Activity Monitor, Windows Services Manager, etc). +Inconsistencies and breaking changes within the _operating systems process +interface_ make synchronization with these applications unreliable. + ## `process.traceDeprecation` - -Enable experimental top-level `await` keyword support, available only in ES -module scripts. - -(See also `--experimental-repl-await`.) - ### `--experimental-vm-modules` + +* `fn` {Function} The function to bind to the current execution context. +* `type` {string} An optional name to associate with the underlying + `AsyncResource`. + +Binds the given function to the current execution context. + +The returned function will have an `asyncResource` property referencing +the `AsyncResource` to which the function is bound. + +#### `asyncResource.bind(fn)` + + +* `fn` {Function} The function to bind to the current `AsyncResource`. + +Binds the given function to execute to this `AsyncResource`'s scope. + +The returned function will have an `asyncResource` property referencing +the `AsyncResource` to which the function is bound. + #### `asyncResource.runInAsyncScope(fn[, thisArg, ...args])` In order to be loaded from multiple Node.js environments, such as a main thread and a Worker thread, an add-on needs to either: @@ -254,6 +260,11 @@ down. If necessary, such hooks can be removed using `RemoveEnvironmentCleanupHook()` before they are run, which has the same signature. Callbacks are run in last-in first-out order. +If necessary, there is an additional pair of `AddEnvironmentCleanupHook()` +and `RemoveEnvironmentCleanupHook()` overloads, where the cleanup hook takes a +callback function. This can be used for shutting down asynchronous resources, +for example any libuv handles registered by the addon. + The following `addon.cc` uses `AddEnvironmentCleanupHook`: ```cpp diff --git a/doc/api/n-api.md b/doc/api/n-api.md index bc02572bf07ed8..7689c67b183fe1 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -1550,10 +1550,12 @@ and will lead the process to abort. The hooks will be called in reverse order, i.e. the most recently added one will be called first. -Removing this hook can be done by using `napi_remove_env_cleanup_hook`. +Removing this hook can be done by using [`napi_remove_env_cleanup_hook`][]. Typically, that happens when the resource for which this hook was added is being torn down anyway. +For asynchronous cleanup, [`napi_add_async_cleanup_hook`][] is available. + #### napi_remove_env_cleanup_hook + +> Stability: 1 - Experimental + +```c +NAPI_EXTERN napi_status napi_add_async_cleanup_hook( + napi_env env, + void (*fun)(void* arg, void(* cb)(void*), void* cbarg), + void* arg, + napi_async_cleanup_hook_handle* remove_handle); +``` + +Registers `fun` as a function to be run with the `arg` parameter once the +current Node.js environment exits. Unlike [`napi_add_env_cleanup_hook`][], +the hook is allowed to be asynchronous in this case, and must invoke the passed +`cb()` function with `cbarg` once all asynchronous activity is finished. + +Otherwise, behavior generally matches that of [`napi_add_env_cleanup_hook`][]. + +If `remove_handle` is not `NULL`, an opaque value will be stored in it +that must later be passed to [`napi_remove_async_cleanup_hook`][], +regardless of whether the hook has already been invoked. +Typically, that happens when the resource for which this hook was added +is being torn down anyway. + +#### napi_remove_async_cleanup_hook + + +> Stability: 1 - Experimental + +```c +NAPI_EXTERN napi_status napi_remove_async_cleanup_hook( + napi_env env, + napi_async_cleanup_hook_handle remove_handle); +``` + +Unregisters the cleanup hook corresponding to `remove_handle`. This will prevent +the hook from being executed, unless it has already started executing. +This must be called on any `napi_async_cleanup_hook_handle` value retrieved +from [`napi_add_async_cleanup_hook`][]. + ## Module registration N-API modules are registered in a manner similar to other modules except that instead of using the `NODE_MODULE` macro the following @@ -5704,6 +5752,7 @@ This API may only be called from the main thread. [`Worker`]: worker_threads.html#worker_threads_class_worker [`global`]: globals.html#globals_global [`init` hooks]: async_hooks.html#async_hooks_init_asyncid_type_triggerasyncid_resource +[`napi_add_async_cleanup_hook`]: #n_api_napi_add_async_cleanup_hook [`napi_add_env_cleanup_hook`]: #n_api_napi_add_env_cleanup_hook [`napi_add_finalizer`]: #n_api_napi_add_finalizer [`napi_async_complete_callback`]: #n_api_napi_async_complete_callback @@ -5744,6 +5793,8 @@ This API may only be called from the main thread. [`napi_queue_async_work`]: #n_api_napi_queue_async_work [`napi_reference_ref`]: #n_api_napi_reference_ref [`napi_reference_unref`]: #n_api_napi_reference_unref +[`napi_remove_async_cleanup_hook`]: #n_api_napi_remove_async_cleanup_hook +[`napi_remove_env_cleanup_hook`]: #n_api_napi_remove_env_cleanup_hook [`napi_set_instance_data`]: #n_api_napi_set_instance_data [`napi_set_property`]: #n_api_napi_set_property [`napi_threadsafe_function_call_js`]: #n_api_napi_threadsafe_function_call_js diff --git a/src/api/hooks.cc b/src/api/hooks.cc index 037bdda6f41c82..3b16c0350d8a84 100644 --- a/src/api/hooks.cc +++ b/src/api/hooks.cc @@ -73,8 +73,35 @@ int EmitExit(Environment* env) { .ToChecked(); } +typedef void (*CleanupHook)(void* arg); +typedef void (*AsyncCleanupHook)(void* arg, void(*)(void*), void*); + +struct AsyncCleanupHookInfo final { + Environment* env; + AsyncCleanupHook fun; + void* arg; + bool started = false; + // Use a self-reference to make sure the storage is kept alive while the + // cleanup hook is registered but not yet finished. + std::shared_ptr self; +}; + +// Opaque type that is basically an alias for `shared_ptr` +// (but not publicly so for easier ABI/API changes). In particular, +// std::shared_ptr does not generally maintain a consistent ABI even on a +// specific platform. +struct ACHHandle final { + std::shared_ptr info; +}; +// This is implemented as an operator on a struct because otherwise you can't +// default-initialize AsyncCleanupHookHandle, because in C++ for a +// std::unique_ptr to be default-initializable the deleter type also needs +// to be default-initializable; in particular, function types don't satisfy +// this. +void DeleteACHHandle::operator ()(ACHHandle* handle) const { delete handle; } + void AddEnvironmentCleanupHook(Isolate* isolate, - void (*fun)(void* arg), + CleanupHook fun, void* arg) { Environment* env = Environment::GetCurrent(isolate); CHECK_NOT_NULL(env); @@ -82,13 +109,50 @@ void AddEnvironmentCleanupHook(Isolate* isolate, } void RemoveEnvironmentCleanupHook(Isolate* isolate, - void (*fun)(void* arg), + CleanupHook fun, void* arg) { Environment* env = Environment::GetCurrent(isolate); CHECK_NOT_NULL(env); env->RemoveCleanupHook(fun, arg); } +static void FinishAsyncCleanupHook(void* arg) { + AsyncCleanupHookInfo* info = static_cast(arg); + std::shared_ptr keep_alive = info->self; + + info->env->DecreaseWaitingRequestCounter(); + info->self.reset(); +} + +static void RunAsyncCleanupHook(void* arg) { + AsyncCleanupHookInfo* info = static_cast(arg); + info->env->IncreaseWaitingRequestCounter(); + info->started = true; + info->fun(info->arg, FinishAsyncCleanupHook, info); +} + +AsyncCleanupHookHandle AddEnvironmentCleanupHook( + Isolate* isolate, + AsyncCleanupHook fun, + void* arg) { + Environment* env = Environment::GetCurrent(isolate); + CHECK_NOT_NULL(env); + auto info = std::make_shared(); + info->env = env; + info->fun = fun; + info->arg = arg; + info->self = info; + env->AddCleanupHook(RunAsyncCleanupHook, info.get()); + return AsyncCleanupHookHandle(new ACHHandle { info }); +} + +void RemoveEnvironmentCleanupHook( + AsyncCleanupHookHandle handle) { + if (handle->info->started) return; + handle->info->self.reset(); + handle->info->env->RemoveCleanupHook(RunAsyncCleanupHook, handle->info.get()); +} + async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) { Environment* env = Environment::GetCurrent(isolate); if (env == nullptr) return -1; diff --git a/src/node.h b/src/node.h index 71273d6db9c6ed..1914e72ee8fa43 100644 --- a/src/node.h +++ b/src/node.h @@ -872,6 +872,20 @@ NODE_EXTERN void RemoveEnvironmentCleanupHook(v8::Isolate* isolate, void (*fun)(void* arg), void* arg); +/* These are async equivalents of the above. After the cleanup hook is invoked, + * `cb(cbarg)` *must* be called, and attempting to remove the cleanup hook will + * have no effect. */ +struct ACHHandle; +struct NODE_EXTERN DeleteACHHandle { void operator()(ACHHandle*) const; }; +typedef std::unique_ptr AsyncCleanupHookHandle; + +NODE_EXTERN AsyncCleanupHookHandle AddEnvironmentCleanupHook( + v8::Isolate* isolate, + void (*fun)(void* arg, void (*cb)(void*), void* cbarg), + void* arg); + +NODE_EXTERN void RemoveEnvironmentCleanupHook(AsyncCleanupHookHandle holder); + /* Returns the id of the current execution context. If the return value is * zero then no execution has been set. This will happen if the user handles * I/O from native code. */ diff --git a/src/node_api.cc b/src/node_api.cc index bb203fc03c310f..8f5823d7820b38 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -518,6 +518,38 @@ napi_status napi_remove_env_cleanup_hook(napi_env env, return napi_ok; } +struct napi_async_cleanup_hook_handle__ { + node::AsyncCleanupHookHandle handle; +}; + +napi_status napi_add_async_cleanup_hook( + napi_env env, + void (*fun)(void* arg, void(* cb)(void*), void* cbarg), + void* arg, + napi_async_cleanup_hook_handle* remove_handle) { + CHECK_ENV(env); + CHECK_ARG(env, fun); + + auto handle = node::AddEnvironmentCleanupHook(env->isolate, fun, arg); + if (remove_handle != nullptr) { + *remove_handle = new napi_async_cleanup_hook_handle__ { std::move(handle) }; + } + + return napi_clear_last_error(env); +} + +napi_status napi_remove_async_cleanup_hook( + napi_env env, + napi_async_cleanup_hook_handle remove_handle) { + CHECK_ENV(env); + CHECK_ARG(env, remove_handle); + + node::RemoveEnvironmentCleanupHook(std::move(remove_handle->handle)); + delete remove_handle; + + return napi_clear_last_error(env); +} + napi_status napi_fatal_exception(napi_env env, napi_value err) { NAPI_PREAMBLE(env); CHECK_ARG(env, err); diff --git a/src/node_api.h b/src/node_api.h index 2f1b45572d8130..4f3eb8f2caae63 100644 --- a/src/node_api.h +++ b/src/node_api.h @@ -250,6 +250,20 @@ napi_ref_threadsafe_function(napi_env env, napi_threadsafe_function func); #endif // NAPI_VERSION >= 4 +#ifdef NAPI_EXPERIMENTAL + +NAPI_EXTERN napi_status napi_add_async_cleanup_hook( + napi_env env, + void (*fun)(void* arg, void(* cb)(void*), void* cbarg), + void* arg, + napi_async_cleanup_hook_handle* remove_handle); + +NAPI_EXTERN napi_status napi_remove_async_cleanup_hook( + napi_env env, + napi_async_cleanup_hook_handle remove_handle); + +#endif // NAPI_EXPERIMENTAL + EXTERN_C_END #endif // SRC_NODE_API_H_ diff --git a/src/node_api_types.h b/src/node_api_types.h index 1c9a2b8aa21889..b8711d3eddc408 100644 --- a/src/node_api_types.h +++ b/src/node_api_types.h @@ -41,4 +41,8 @@ typedef struct { const char* release; } napi_node_version; +#ifdef NAPI_EXPERIMENTAL +typedef struct napi_async_cleanup_hook_handle__* napi_async_cleanup_hook_handle; +#endif // NAPI_EXPERIMENTAL + #endif // SRC_NODE_API_TYPES_H_ diff --git a/test/addons/async-cleanup-hook/binding.cc b/test/addons/async-cleanup-hook/binding.cc new file mode 100644 index 00000000000000..d18da7a094f71a --- /dev/null +++ b/test/addons/async-cleanup-hook/binding.cc @@ -0,0 +1,59 @@ +#include +#include +#include + +void MustNotCall(void* arg, void(*cb)(void*), void* cbarg) { + assert(0); +} + +struct AsyncData { + uv_async_t async; + v8::Isolate* isolate; + node::AsyncCleanupHookHandle handle; + void (*done_cb)(void*); + void* done_arg; +}; + +void AsyncCleanupHook(void* arg, void(*cb)(void*), void* cbarg) { + AsyncData* data = static_cast(arg); + uv_loop_t* loop = node::GetCurrentEventLoop(data->isolate); + assert(loop != nullptr); + int err = uv_async_init(loop, &data->async, [](uv_async_t* async) { + AsyncData* data = static_cast(async->data); + // Attempting to remove the cleanup hook here should be a no-op since it + // has already been started. + node::RemoveEnvironmentCleanupHook(std::move(data->handle)); + + uv_close(reinterpret_cast(async), [](uv_handle_t* handle) { + AsyncData* data = static_cast(handle->data); + data->done_cb(data->done_arg); + delete data; + }); + }); + assert(err == 0); + + data->async.data = data; + data->done_cb = cb; + data->done_arg = cbarg; + uv_async_send(&data->async); +} + +void Initialize(v8::Local exports, + v8::Local module, + v8::Local context) { + AsyncData* data = new AsyncData(); + data->isolate = context->GetIsolate(); + auto handle = node::AddEnvironmentCleanupHook( + context->GetIsolate(), + AsyncCleanupHook, + data); + data->handle = std::move(handle); + + auto must_not_call_handle = node::AddEnvironmentCleanupHook( + context->GetIsolate(), + MustNotCall, + nullptr); + node::RemoveEnvironmentCleanupHook(std::move(must_not_call_handle)); +} + +NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize) diff --git a/test/addons/async-cleanup-hook/binding.gyp b/test/addons/async-cleanup-hook/binding.gyp new file mode 100644 index 00000000000000..55fbe7050f18e4 --- /dev/null +++ b/test/addons/async-cleanup-hook/binding.gyp @@ -0,0 +1,9 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': [ 'binding.cc' ], + 'includes': ['../common.gypi'], + } + ] +} diff --git a/test/addons/async-cleanup-hook/test.js b/test/addons/async-cleanup-hook/test.js new file mode 100644 index 00000000000000..55cc2517a59bc8 --- /dev/null +++ b/test/addons/async-cleanup-hook/test.js @@ -0,0 +1,8 @@ +'use strict'; +const common = require('../../common'); +const path = require('path'); +const { Worker } = require('worker_threads'); +const binding = path.resolve(__dirname, `./build/${common.buildType}/binding`); + +const w = new Worker(`require(${JSON.stringify(binding)})`, { eval: true }); +w.on('exit', common.mustCall(() => require(binding))); diff --git a/test/node-api/test_async_cleanup_hook/binding.c b/test/node-api/test_async_cleanup_hook/binding.c new file mode 100644 index 00000000000000..f0c9cd97a26c48 --- /dev/null +++ b/test/node-api/test_async_cleanup_hook/binding.c @@ -0,0 +1,82 @@ +#define NAPI_EXPERIMENTAL +#include "node_api.h" +#include "assert.h" +#include "uv.h" +#include +#include "../../js-native-api/common.h" + +void MustNotCall(void* arg, void(*cb)(void*), void* cbarg) { + assert(0); +} + +struct AsyncData { + uv_async_t async; + napi_env env; + napi_async_cleanup_hook_handle handle; + void (*done_cb)(void*); + void* done_arg; +}; + +struct AsyncData* CreateAsyncData() { + struct AsyncData* data = (struct AsyncData*) malloc(sizeof(struct AsyncData)); + data->handle = NULL; + return data; +} + +void AfterCleanupHookTwo(uv_handle_t* handle) { + struct AsyncData* data = (struct AsyncData*) handle->data; + data->done_cb(data->done_arg); + free(data); +} + +void AfterCleanupHookOne(uv_async_t* async) { + struct AsyncData* data = (struct AsyncData*) async->data; + if (data->handle != NULL) { + // Verify that removing the hook is okay between starting and finishing + // of its execution. + napi_status status = + napi_remove_async_cleanup_hook(data->env, data->handle); + assert(status == napi_ok); + } + + uv_close((uv_handle_t*) async, AfterCleanupHookTwo); +} + +void AsyncCleanupHook(void* arg, void(*cb)(void*), void* cbarg) { + struct AsyncData* data = (struct AsyncData*) arg; + uv_loop_t* loop; + napi_status status = napi_get_uv_event_loop(data->env, &loop); + assert(status == napi_ok); + int err = uv_async_init(loop, &data->async, AfterCleanupHookOne); + assert(err == 0); + + data->async.data = data; + data->done_cb = cb; + data->done_arg = cbarg; + uv_async_send(&data->async); +} + +napi_value Init(napi_env env, napi_value exports) { + { + struct AsyncData* data = CreateAsyncData(); + data->env = env; + napi_add_async_cleanup_hook(env, AsyncCleanupHook, data, &data->handle); + } + + { + struct AsyncData* data = CreateAsyncData(); + data->env = env; + napi_add_async_cleanup_hook(env, AsyncCleanupHook, data, NULL); + } + + { + napi_async_cleanup_hook_handle must_not_call_handle; + napi_add_async_cleanup_hook( + env, MustNotCall, NULL, &must_not_call_handle); + napi_remove_async_cleanup_hook(env, must_not_call_handle); + } + + return NULL; +} + +NAPI_MODULE(NODE_GYP_MODULE_NAME, Init) diff --git a/test/node-api/test_async_cleanup_hook/binding.gyp b/test/node-api/test_async_cleanup_hook/binding.gyp new file mode 100644 index 00000000000000..23daf507916ff6 --- /dev/null +++ b/test/node-api/test_async_cleanup_hook/binding.gyp @@ -0,0 +1,9 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'defines': [ 'V8_DEPRECATION_WARNINGS=1' ], + 'sources': [ 'binding.c' ] + } + ] +} diff --git a/test/node-api/test_async_cleanup_hook/test.js b/test/node-api/test_async_cleanup_hook/test.js new file mode 100644 index 00000000000000..55cc2517a59bc8 --- /dev/null +++ b/test/node-api/test_async_cleanup_hook/test.js @@ -0,0 +1,8 @@ +'use strict'; +const common = require('../../common'); +const path = require('path'); +const { Worker } = require('worker_threads'); +const binding = path.resolve(__dirname, `./build/${common.buildType}/binding`); + +const w = new Worker(`require(${JSON.stringify(binding)})`, { eval: true }); +w.on('exit', common.mustCall(() => require(binding))); From db6f9bd43a49023a39df0f1a831a0488b5ed5bc1 Mon Sep 17 00:00:00 2001 From: Gerhard Stoebich <18708370+Flarna@users.noreply.github.com> Date: Mon, 3 Aug 2020 23:46:49 +0200 Subject: [PATCH 70/79] async_hooks: avoid GC tracking of AsyncResource in ALS Manually destroy the AsyncResource created by AsyncLocalStore.run() to avoid unneeded GC tracking in case a destroy hooks is present. PR-URL: https://github.com/nodejs/node/pull/34653 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell --- lib/async_hooks.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/async_hooks.js b/lib/async_hooks.js index 758c4eab10fe83..7dd888b61f79f9 100644 --- a/lib/async_hooks.js +++ b/lib/async_hooks.js @@ -253,6 +253,7 @@ const storageHook = createHook({ } }); +const defaultAlsResourceOpts = { requireManualDestroy: true }; class AsyncLocalStorage { constructor() { this.kResourceStore = Symbol('kResourceStore'); @@ -293,8 +294,11 @@ class AsyncLocalStorage { if (ObjectIs(store, this.getStore())) { return callback(...args); } - const resource = new AsyncResource('AsyncLocalStorage'); - return resource.runInAsyncScope(() => { + const resource = new AsyncResource('AsyncLocalStorage', + defaultAlsResourceOpts); + // Calling emitDestroy before runInAsyncScope avoids a try/finally + // It is ok because emitDestroy only schedules calling the hook + return resource.emitDestroy().runInAsyncScope(() => { this.enterWith(store); return callback(...args); }); From 4ed89a3c23c955fb18c836c6d6108d8890db05b1 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 7 Aug 2020 12:48:45 +0200 Subject: [PATCH 71/79] n-api: fix use-after-free with napi_remove_async_cleanup_hook Fixes: https://github.com/nodejs/node/issues/34657 Refs: https://github.com/nodejs/node/pull/34572 PR-URL: https://github.com/nodejs/node/pull/34662 Reviewed-By: Gabriel Schulhof Reviewed-By: James M Snell --- src/node_api.cc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/node_api.cc b/src/node_api.cc index 8f5823d7820b38..4fbab771d58400 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -533,6 +533,7 @@ napi_status napi_add_async_cleanup_hook( auto handle = node::AddEnvironmentCleanupHook(env->isolate, fun, arg); if (remove_handle != nullptr) { *remove_handle = new napi_async_cleanup_hook_handle__ { std::move(handle) }; + env->Ref(); } return napi_clear_last_error(env); @@ -547,6 +548,11 @@ napi_status napi_remove_async_cleanup_hook( node::RemoveEnvironmentCleanupHook(std::move(remove_handle->handle)); delete remove_handle; + // Release the `env` handle asynchronously since it would be surprising if + // a call to a N-API function would destroy `env` synchronously. + static_cast(env)->node_env() + ->SetImmediate([env](node::Environment*) { env->Unref(); }); + return napi_clear_last_error(env); } From a944dab7076331944aeefd2802ec252811e9a702 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 4 Aug 2020 16:23:26 -0700 Subject: [PATCH 72/79] doc: use _Class Method_ in async_hooks.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We use _Class Method_ rather than _static_ in documentation headers in buffer.md and crypto.md. We use _static_ in one place in async_hooks.md. Change to _Class Method_ for consistency. PR-URL: https://github.com/nodejs/node/pull/34626 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Gerhard Stöbich Reviewed-By: Joyee Cheung --- doc/api/async_hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index a1fa08fa563edd..81ca1ef51f007f 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -727,7 +727,7 @@ class DBQuery extends AsyncResource { } ``` -#### `static AsyncResource.bind(fn[, type])` +#### Class Method: `AsyncResource.bind(fn[, type])` From e97fe4b6307023f42c0e8617718693e991e4670a Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 31 Jul 2020 17:58:53 +0200 Subject: [PATCH 73/79] src: fix linter failures Fix linter failures when running the linter on all source files. PR-URL: https://github.com/nodejs/node/pull/34582 Refs: https://github.com/nodejs/node/pull/34565 Reviewed-By: James M Snell Reviewed-By: Richard Lau Reviewed-By: David Carlier Reviewed-By: Luigi Pinca --- src/api/hooks.cc | 2 +- src/inspector/main_thread_interface.cc | 2 +- src/node_report.cc | 4 +--- test/addons/async-hooks-promise/binding.cc | 1 - test/addons/dlopen-ping-pong/binding.cc | 1 - test/addons/non-node-context/binding.cc | 3 --- test/addons/repl-domain-abort/binding.cc | 2 +- test/addons/uv-handle-leak/binding.cc | 1 - test/addons/worker-addon/binding.cc | 2 -- test/cctest/test_base64.cc | 2 +- test/cctest/test_util.cc | 23 ++++++++++------------ test/embedding/embedtest.cc | 2 +- 12 files changed, 16 insertions(+), 29 deletions(-) diff --git a/src/api/hooks.cc b/src/api/hooks.cc index 3b16c0350d8a84..e1536193f95730 100644 --- a/src/api/hooks.cc +++ b/src/api/hooks.cc @@ -10,10 +10,10 @@ using v8::HandleScope; using v8::Integer; using v8::Isolate; using v8::Local; +using v8::NewStringType; using v8::Object; using v8::String; using v8::Value; -using v8::NewStringType; void RunAtExit(Environment* env) { env->RunAtExitCallbacks(); diff --git a/src/inspector/main_thread_interface.cc b/src/inspector/main_thread_interface.cc index a15cd52d239e40..0cf75a37146729 100644 --- a/src/inspector/main_thread_interface.cc +++ b/src/inspector/main_thread_interface.cc @@ -14,8 +14,8 @@ namespace node { namespace inspector { namespace { -using v8_inspector::StringView; using v8_inspector::StringBuffer; +using v8_inspector::StringView; template class DeletableWrapper : public Deletable { diff --git a/src/node_report.cc b/src/node_report.cc index c93e03afe63918..e7bfe7fef09d14 100644 --- a/src/node_report.cc +++ b/src/node_report.cc @@ -43,13 +43,11 @@ using v8::HeapSpaceStatistics; using v8::HeapStatistics; using v8::Isolate; using v8::Local; -using v8::Number; using v8::Object; -using v8::StackTrace; using v8::String; using v8::TryCatch; -using v8::Value; using v8::V8; +using v8::Value; namespace per_process = node::per_process; diff --git a/test/addons/async-hooks-promise/binding.cc b/test/addons/async-hooks-promise/binding.cc index 452cbda8793aa1..8fe6b9471bcee5 100644 --- a/test/addons/async-hooks-promise/binding.cc +++ b/test/addons/async-hooks-promise/binding.cc @@ -6,7 +6,6 @@ namespace { using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; -using v8::NewStringType; using v8::Object; using v8::Promise; using v8::String; diff --git a/test/addons/dlopen-ping-pong/binding.cc b/test/addons/dlopen-ping-pong/binding.cc index c8711f09aedac6..be33708c9317d3 100644 --- a/test/addons/dlopen-ping-pong/binding.cc +++ b/test/addons/dlopen-ping-pong/binding.cc @@ -17,7 +17,6 @@ using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::Object; -using v8::NewStringType; using v8::String; using v8::Value; diff --git a/test/addons/non-node-context/binding.cc b/test/addons/non-node-context/binding.cc index 6fe776b7c60c3d..8423d2b1d7a5a5 100644 --- a/test/addons/non-node-context/binding.cc +++ b/test/addons/non-node-context/binding.cc @@ -5,12 +5,9 @@ namespace { using v8::Context; -using v8::Function; -using v8::FunctionTemplate; using v8::Isolate; using v8::Local; using v8::MaybeLocal; -using v8::NewStringType; using v8::Object; using v8::Script; using v8::String; diff --git a/test/addons/repl-domain-abort/binding.cc b/test/addons/repl-domain-abort/binding.cc index 3e716443540229..f5e82d3718ccac 100644 --- a/test/addons/repl-domain-abort/binding.cc +++ b/test/addons/repl-domain-abort/binding.cc @@ -25,8 +25,8 @@ using v8::Boolean; using v8::Function; using v8::FunctionCallbackInfo; -using v8::Local; using v8::Isolate; +using v8::Local; using v8::Object; using v8::Value; diff --git a/test/addons/uv-handle-leak/binding.cc b/test/addons/uv-handle-leak/binding.cc index 1b769b141c0076..20ddfac6802e97 100644 --- a/test/addons/uv-handle-leak/binding.cc +++ b/test/addons/uv-handle-leak/binding.cc @@ -6,7 +6,6 @@ using v8::Context; using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; -using v8::Object; using v8::Value; // Give these things names in the public namespace so that we can see diff --git a/test/addons/worker-addon/binding.cc b/test/addons/worker-addon/binding.cc index 01c857c43ebcfc..d5a07ff20959e8 100644 --- a/test/addons/worker-addon/binding.cc +++ b/test/addons/worker-addon/binding.cc @@ -6,8 +6,6 @@ #include using v8::Context; -using v8::HandleScope; -using v8::Isolate; using v8::Local; using v8::Object; using v8::Value; diff --git a/test/cctest/test_base64.cc b/test/cctest/test_base64.cc index 5e39a1052bc057..be61618f9086ed 100644 --- a/test/cctest/test_base64.cc +++ b/test/cctest/test_base64.cc @@ -5,8 +5,8 @@ #include "gtest/gtest.h" -using node::base64_encode; using node::base64_decode; +using node::base64_encode; TEST(Base64Test, Encode) { auto test = [](const char* string, const char* base64_string) { diff --git a/test/cctest/test_util.cc b/test/cctest/test_util.cc index 6cfd5d317f7982..85c5a6a7fe43ae 100644 --- a/test/cctest/test_util.cc +++ b/test/cctest/test_util.cc @@ -3,6 +3,16 @@ #include "env-inl.h" #include "gtest/gtest.h" +using node::Calloc; +using node::Malloc; +using node::MaybeStackBuffer; +using node::SPrintF; +using node::StringEqualNoCase; +using node::StringEqualNoCaseN; +using node::ToLower; +using node::UncheckedCalloc; +using node::UncheckedMalloc; + TEST(UtilTest, ListHead) { struct Item { node::ListNode node_; }; typedef node::ListHead List; @@ -58,7 +68,6 @@ TEST(UtilTest, ListHead) { } TEST(UtilTest, StringEqualNoCase) { - using node::StringEqualNoCase; EXPECT_FALSE(StringEqualNoCase("a", "b")); EXPECT_TRUE(StringEqualNoCase("", "")); EXPECT_TRUE(StringEqualNoCase("equal", "equal")); @@ -69,7 +78,6 @@ TEST(UtilTest, StringEqualNoCase) { } TEST(UtilTest, StringEqualNoCaseN) { - using node::StringEqualNoCaseN; EXPECT_FALSE(StringEqualNoCaseN("a", "b", strlen("a"))); EXPECT_TRUE(StringEqualNoCaseN("", "", strlen(""))); EXPECT_TRUE(StringEqualNoCaseN("equal", "equal", strlen("equal"))); @@ -84,7 +92,6 @@ TEST(UtilTest, StringEqualNoCaseN) { } TEST(UtilTest, ToLower) { - using node::ToLower; EXPECT_EQ('0', ToLower('0')); EXPECT_EQ('a', ToLower('a')); EXPECT_EQ('a', ToLower('A')); @@ -98,7 +105,6 @@ TEST(UtilTest, ToLower) { } while (0) TEST(UtilTest, Malloc) { - using node::Malloc; TEST_AND_FREE(Malloc(0)); TEST_AND_FREE(Malloc(1)); TEST_AND_FREE(Malloc(0)); @@ -106,7 +112,6 @@ TEST(UtilTest, Malloc) { } TEST(UtilTest, Calloc) { - using node::Calloc; TEST_AND_FREE(Calloc(0)); TEST_AND_FREE(Calloc(1)); TEST_AND_FREE(Calloc(0)); @@ -114,7 +119,6 @@ TEST(UtilTest, Calloc) { } TEST(UtilTest, UncheckedMalloc) { - using node::UncheckedMalloc; TEST_AND_FREE(UncheckedMalloc(0)); TEST_AND_FREE(UncheckedMalloc(1)); TEST_AND_FREE(UncheckedMalloc(0)); @@ -122,7 +126,6 @@ TEST(UtilTest, UncheckedMalloc) { } TEST(UtilTest, UncheckedCalloc) { - using node::UncheckedCalloc; TEST_AND_FREE(UncheckedCalloc(0)); TEST_AND_FREE(UncheckedCalloc(1)); TEST_AND_FREE(UncheckedCalloc(0)); @@ -131,8 +134,6 @@ TEST(UtilTest, UncheckedCalloc) { template static void MaybeStackBufferBasic() { - using node::MaybeStackBuffer; - MaybeStackBuffer buf; size_t old_length; size_t old_capacity; @@ -211,8 +212,6 @@ static void MaybeStackBufferBasic() { } TEST(UtilTest, MaybeStackBuffer) { - using node::MaybeStackBuffer; - MaybeStackBufferBasic(); MaybeStackBufferBasic(); @@ -254,8 +253,6 @@ TEST(UtilTest, MaybeStackBuffer) { } TEST(UtilTest, SPrintF) { - using node::SPrintF; - // %d, %u and %s all do the same thing. The actual C++ type is used to infer // the right representation. EXPECT_EQ(SPrintF("%s", false), "false"); diff --git a/test/embedding/embedtest.cc b/test/embedding/embedtest.cc index a927167ea6a921..21e5ac713ed017 100644 --- a/test/embedding/embedtest.cc +++ b/test/embedding/embedtest.cc @@ -16,8 +16,8 @@ using v8::Local; using v8::Locker; using v8::MaybeLocal; using v8::SealHandleScope; -using v8::Value; using v8::V8; +using v8::Value; static int RunNodeInstance(MultiIsolatePlatform* platform, const std::vector& args, From af0cfeb1bbbe77a19ef91c3ed467f377392e9d26 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 31 Jul 2020 17:59:38 +0200 Subject: [PATCH 74/79] tools: fix C++ import checker argument expansion Makefile assumes that it can pass a list of files to the import checker, whereas the import checker expects a single argument that is interpreted as a blob. Fix that mismatch by accepting multiple arguments in the import checker. Refs: https://github.com/nodejs/node/pull/34565 PR-URL: https://github.com/nodejs/node/pull/34582 Reviewed-By: James M Snell Reviewed-By: Richard Lau Reviewed-By: David Carlier Reviewed-By: Luigi Pinca --- tools/checkimports.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/checkimports.py b/tools/checkimports.py index 609a75f542748f..b94919e3cc47e4 100755 --- a/tools/checkimports.py +++ b/tools/checkimports.py @@ -5,7 +5,7 @@ import io import re import sys - +import itertools def do_exist(file_name, lines, imported): if not any(not re.match('using \w+::{0};'.format(imported), line) and @@ -41,5 +41,10 @@ def is_valid(file_name): return valid if __name__ == '__main__': - files = glob.iglob(sys.argv[1] if len(sys.argv) > 1 else 'src/*.cc') - sys.exit(0 if all(map(is_valid, files)) else 1) + if len(sys.argv) > 1: + files = [] + for pattern in sys.argv[1:]: + files = itertools.chain(files, glob.iglob(pattern)) + else: + files = glob.iglob('src/*.cc') + sys.exit(0 if all(list(map(is_valid, files))) else 1) From 5b5f5f9343e4546a982f660a5795f48c55c9b0ca Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 6 Aug 2020 16:38:11 -0700 Subject: [PATCH 75/79] doc: tidy some addons.md text PR-URL: https://github.com/nodejs/node/pull/34654 Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat Reviewed-By: Luigi Pinca --- doc/api/addons.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/api/addons.md b/doc/api/addons.md index 195f28839d5ac9..36d3922b795bce 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -256,14 +256,14 @@ void AddEnvironmentCleanupHook(v8::Isolate* isolate, ``` This function adds a hook that will run before a given Node.js instance shuts -down. If necessary, such hooks can be removed using -`RemoveEnvironmentCleanupHook()` before they are run, which has the same -signature. Callbacks are run in last-in first-out order. +down. If necessary, such hooks can be removed before they are run using +`RemoveEnvironmentCleanupHook()`, which has the same signature. Callbacks are +run in last-in first-out order. If necessary, there is an additional pair of `AddEnvironmentCleanupHook()` and `RemoveEnvironmentCleanupHook()` overloads, where the cleanup hook takes a callback function. This can be used for shutting down asynchronous resources, -for example any libuv handles registered by the addon. +such as any libuv handles registered by the addon. The following `addon.cc` uses `AddEnvironmentCleanupHook`: From 4efc5f66faaa7f61b046b5614441bd6124c9fc86 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 4 Aug 2020 09:13:09 -0700 Subject: [PATCH 76/79] lib: use non-symbols in isURLInstance check PR-URL: https://github.com/nodejs/node/pull/34622 Reviewed-By: James M Snell Reviewed-By: Rich Trott --- lib/internal/url.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index c0b8c17d098708..71b0dd26e2735a 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -1391,8 +1391,7 @@ function pathToFileURL(filepath) { } function isURLInstance(fileURLOrPath) { - return fileURLOrPath != null && fileURLOrPath[searchParams] && - fileURLOrPath[searchParams][searchParams]; + return fileURLOrPath != null && fileURLOrPath.href && fileURLOrPath.origin; } function toPathIfFileURL(fileURLOrPath) { From 41d0cf7d581e24f7e09fee999c8f515ad78289c6 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 6 Aug 2020 22:19:11 -0700 Subject: [PATCH 77/79] doc: use _Static method_ instead of _Class Method_ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our docs describe static methods as Class Methods which seems idiosyncratic for JavaScript. Align with MDN which calls them static methods. Refs: https://developer.mozilla.org/en-US/docs/MDN/Contribute/Structures/API_references/What_does_an_API_reference_need JSON format for our docs will still use the key name `classMethods` for this. I would like to change it to `staticMethods` but I don't know if that will break things for consumers. So, leaving it alone. It's a machine-consumable label more than a human-readable so I can live with that. PR-URL: https://github.com/nodejs/node/pull/34659 Reviewed-By: Michaël Zasso Reviewed-By: James M Snell Reviewed-By: Gerhard Stöbich Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat --- doc/api/async_hooks.md | 2 +- doc/api/buffer.md | 40 +++++++++---------- doc/api/crypto.md | 2 +- doc/api/deprecations.md | 16 ++++---- doc/api/dgram.md | 2 +- doc/api/fs.md | 2 +- doc/api/http.md | 2 +- doc/api/util.md | 2 +- doc/api/worker_threads.md | 2 +- test/doctool/test-doctool-html.js | 6 +-- test/doctool/test-doctool-json.js | 4 +- .../doc_with_backticks_in_headings.md | 2 +- test/fixtures/order_of_end_tags_5873.md | 2 +- tools/doc/json.js | 2 +- 14 files changed, 43 insertions(+), 43 deletions(-) diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 81ca1ef51f007f..745a2376257ed9 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -727,7 +727,7 @@ class DBQuery extends AsyncResource { } ``` -#### Class Method: `AsyncResource.bind(fn[, type])` +#### Static method: `AsyncResource.bind(fn[, type])` diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 22ecfc867c5e5a..8cdb910b9f486d 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -284,7 +284,7 @@ Additionally, the [`buf.values()`][], [`buf.keys()`][], and The `Buffer` class is a global type for dealing with binary data directly. It can be constructed in a variety of ways. -### Class Method: `Buffer.alloc(size[, fill[, encoding]])` +### Static method: `Buffer.alloc(size[, fill[, encoding]])` @@ -446,7 +446,7 @@ socket.on('readable', () => { A `TypeError` will be thrown if `size` is not a number. -### Class Method: `Buffer.byteLength(string[, encoding])` +### Static method: `Buffer.byteLength(string[, encoding])` @@ -581,7 +581,7 @@ appropriate for `Buffer.from()` variants. `Buffer.from(array)` and [`Buffer.from(string)`][] may also use the internal `Buffer` pool like [`Buffer.allocUnsafe()`][] does. -### Class Method: `Buffer.from(arrayBuffer[, byteOffset[, length]])` +### Static method: `Buffer.from(arrayBuffer[, byteOffset[, length]])` @@ -632,7 +632,7 @@ A `TypeError` will be thrown if `arrayBuffer` is not an [`ArrayBuffer`][] or a [`SharedArrayBuffer`][] or another type appropriate for `Buffer.from()` variants. -### Class Method: `Buffer.from(buffer)` +### Static method: `Buffer.from(buffer)` @@ -657,7 +657,7 @@ console.log(buf2.toString()); A `TypeError` will be thrown if `buffer` is not a `Buffer` or another type appropriate for `Buffer.from()` variants. -### Class Method: `Buffer.from(object[, offsetOrEncoding[, length]])` +### Static method: `Buffer.from(object[, offsetOrEncoding[, length]])` @@ -691,7 +691,7 @@ const buf = Buffer.from(new Foo(), 'utf8'); A `TypeError` will be thrown if `object` does not have the mentioned methods or is not of another type appropriate for `Buffer.from()` variants. -### Class Method: `Buffer.from(string[, encoding])` +### Static method: `Buffer.from(string[, encoding])` @@ -717,7 +717,7 @@ console.log(buf1.toString('latin1')); A `TypeError` will be thrown if `string` is not a string or another type appropriate for `Buffer.from()` variants. -### Class Method: `Buffer.isBuffer(obj)` +### Static method: `Buffer.isBuffer(obj)` @@ -727,7 +727,7 @@ added: v0.1.101 Returns `true` if `obj` is a `Buffer`, `false` otherwise. -### Class Method: `Buffer.isEncoding(encoding)` +### Static method: `Buffer.isEncoding(encoding)` @@ -3206,13 +3206,13 @@ introducing security vulnerabilities into an application. [RFC 4648, Section 5]: https://tools.ietf.org/html/rfc4648#section-5 [WHATWG Encoding Standard]: https://encoding.spec.whatwg.org/ [`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer -[`Buffer.alloc()`]: #buffer_class_method_buffer_alloc_size_fill_encoding -[`Buffer.allocUnsafe()`]: #buffer_class_method_buffer_allocunsafe_size -[`Buffer.allocUnsafeSlow()`]: #buffer_class_method_buffer_allocunsafeslow_size -[`Buffer.from(array)`]: #buffer_class_method_buffer_from_array -[`Buffer.from(arrayBuf)`]: #buffer_class_method_buffer_from_arraybuffer_byteoffset_length -[`Buffer.from(buffer)`]: #buffer_class_method_buffer_from_buffer -[`Buffer.from(string)`]: #buffer_class_method_buffer_from_string_encoding +[`Buffer.alloc()`]: #buffer_static_method_buffer_alloc_size_fill_encoding +[`Buffer.allocUnsafe()`]: #buffer_static_method_buffer_allocunsafe_size +[`Buffer.allocUnsafeSlow()`]: #buffer_static_method_buffer_allocunsafeslow_size +[`Buffer.from(array)`]: #buffer_static_method_buffer_from_array +[`Buffer.from(arrayBuf)`]: #buffer_static_method_buffer_from_arraybuffer_byteoffset_length +[`Buffer.from(buffer)`]: #buffer_static_method_buffer_from_buffer +[`Buffer.from(string)`]: #buffer_static_method_buffer_from_string_encoding [`Buffer.poolSize`]: #buffer_class_property_buffer_poolsize [`DataView`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView [`ERR_INVALID_BUFFER_SIZE`]: errors.html#ERR_INVALID_BUFFER_SIZE diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 13048337e0ba66..0c872e99823467 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -787,7 +787,7 @@ assert.strictEqual(aliceSecret.toString('hex'), bobSecret.toString('hex')); // OK ``` -### Class Method: `ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]])` +### Static method: `ECDH.convertKey(key, curve[, inputEncoding[, outputEncoding[, format]]])` diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md index 0c68842fe68299..c7583e3a9e97ba 100644 --- a/doc/api/deprecations.md +++ b/doc/api/deprecations.md @@ -2755,10 +2755,10 @@ Type: Documentation-only [`--pending-deprecation`]: cli.html#cli_pending_deprecation [`--throw-deprecation`]: cli.html#cli_throw_deprecation -[`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size -[`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array -[`Buffer.from(buffer)`]: buffer.html#buffer_class_method_buffer_from_buffer -[`Buffer.isBuffer()`]: buffer.html#buffer_class_method_buffer_isbuffer_obj +[`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_static_method_buffer_allocunsafeslow_size +[`Buffer.from(array)`]: buffer.html#buffer_static_method_buffer_from_array +[`Buffer.from(buffer)`]: buffer.html#buffer_static_method_buffer_from_buffer +[`Buffer.isBuffer()`]: buffer.html#buffer_static_method_buffer_isbuffer_obj [`Cipher`]: crypto.html#crypto_class_cipher [`Decipher`]: crypto.html#crypto_class_decipher [`EventEmitter.listenerCount(emitter, eventName)`]: events.html#events_eventemitter_listenercount_emitter_eventname @@ -2870,8 +2870,8 @@ Type: Documentation-only [NIST SP 800-38D]: https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf [RFC 6066]: https://tools.ietf.org/html/rfc6066#section-3 [WHATWG URL API]: url.html#url_the_whatwg_url_api -[alloc]: buffer.html#buffer_class_method_buffer_alloc_size_fill_encoding -[alloc_unsafe_size]: buffer.html#buffer_class_method_buffer_allocunsafe_size -[from_arraybuffer]: buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length -[from_string_encoding]: buffer.html#buffer_class_method_buffer_from_string_encoding +[alloc]: buffer.html#buffer_static_method_buffer_alloc_size_fill_encoding +[alloc_unsafe_size]: buffer.html#buffer_static_method_buffer_allocunsafe_size +[from_arraybuffer]: buffer.html#buffer_static_method_buffer_from_arraybuffer_byteoffset_length +[from_string_encoding]: buffer.html#buffer_static_method_buffer_from_string_encoding [legacy `urlObject`]: url.html#url_legacy_urlobject diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 3cc2ea78297228..462f71ed74c775 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -802,4 +802,4 @@ and `udp6` sockets). The bound address and port can be retrieved using [`socket.bind()`]: #dgram_socket_bind_port_address_callback [IPv6 Zone Indices]: https://en.wikipedia.org/wiki/IPv6_address#Scoped_literal_IPv6_addresses [RFC 4007]: https://tools.ietf.org/html/rfc4007 -[byte length]: buffer.html#buffer_class_method_buffer_bytelength_string_encoding +[byte length]: buffer.html#buffer_static_method_buffer_bytelength_string_encoding diff --git a/doc/api/fs.md b/doc/api/fs.md index adcf875fc5deed..180e89b116528d 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -5855,7 +5855,7 @@ A call to `fs.ftruncate()` or `filehandle.truncate()` can be used to reset the file contents. [`AHAFS`]: https://www.ibm.com/developerworks/aix/library/au-aix_event_infrastructure/ -[`Buffer.byteLength`]: buffer.html#buffer_class_method_buffer_bytelength_string_encoding +[`Buffer.byteLength`]: buffer.html#buffer_static_method_buffer_bytelength_string_encoding [`Buffer`]: buffer.html#buffer_buffer [`FSEvents`]: https://developer.apple.com/documentation/coreservices/file_system_events [`Number.MAX_SAFE_INTEGER`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER diff --git a/doc/api/http.md b/doc/api/http.md index 46067b777484ea..fa60f0c9687cf5 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -2627,7 +2627,7 @@ try { [`'response'`]: #http_event_response [`'upgrade'`]: #http_event_upgrade [`Agent`]: #http_class_http_agent -[`Buffer.byteLength()`]: buffer.html#buffer_class_method_buffer_bytelength_string_encoding +[`Buffer.byteLength()`]: buffer.html#buffer_static_method_buffer_bytelength_string_encoding [`Duplex`]: stream.html#stream_class_stream_duplex [`HPE_HEADER_OVERFLOW`]: errors.html#errors_hpe_header_overflow [`TypeError`]: errors.html#errors_class_typeerror diff --git a/doc/api/util.md b/doc/api/util.md index f21f957bba3eeb..b14c5969f0b416 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -2414,7 +2414,7 @@ util.log('Timestamped message.'); [`Array.isArray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray [`ArrayBuffer.isView()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer/isView [`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer -[`Buffer.isBuffer()`]: buffer.html#buffer_class_method_buffer_isbuffer_obj +[`Buffer.isBuffer()`]: buffer.html#buffer_static_method_buffer_isbuffer_obj [`DataView`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView [`Date`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date [`Error`]: errors.html#errors_class_error diff --git a/doc/api/worker_threads.md b/doc/api/worker_threads.md index 7d1f3509c374c3..9b57d28a3e6dd2 100644 --- a/doc/api/worker_threads.md +++ b/doc/api/worker_threads.md @@ -892,7 +892,7 @@ active handle in the event system. If the worker is already `unref()`ed calling [`ArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer [`AsyncResource`]: async_hooks.html#async_hooks_class_asyncresource [`Buffer`]: buffer.html -[`Buffer.allocUnsafe()`]: buffer.html#buffer_class_method_buffer_allocunsafe_size +[`Buffer.allocUnsafe()`]: buffer.html#buffer_static_method_buffer_allocunsafe_size [`ERR_MISSING_MESSAGE_PORT_IN_TRANSFER_LIST`]: errors.html#errors_err_missing_message_port_in_transfer_list [`ERR_WORKER_NOT_RUNNING`]: errors.html#ERR_WORKER_NOT_RUNNING [`EventEmitter`]: events.html diff --git a/test/doctool/test-doctool-html.js b/test/doctool/test-doctool-html.js index 30221a7fe18b1a..b03bada053761f 100644 --- a/test/doctool/test-doctool-html.js +++ b/test/doctool/test-doctool-html.js @@ -65,9 +65,9 @@ const testData = [ }, { file: fixtures.path('order_of_end_tags_5873.md'), - html: '

ClassMethod: Buffer.from(array) ' + - '#

' + + html: '

Static method: Buffer.from(array) ' + + '#

' + '' diff --git a/test/doctool/test-doctool-json.js b/test/doctool/test-doctool-json.js index 78afc818e9fae0..36d76cfec8236b 100644 --- a/test/doctool/test-doctool-json.js +++ b/test/doctool/test-doctool-json.js @@ -69,7 +69,7 @@ const testData = [ textRaw: 'Subsection', name: 'subsection', classMethods: [{ - textRaw: 'Class Method: Buffer.from(array)', + textRaw: 'Static method: Buffer.from(array)', type: 'classMethod', name: 'from', signatures: [ @@ -181,7 +181,7 @@ const testData = [ params: [] } ], - textRaw: 'Class Method: `Fhqwhgads.again()`', + textRaw: 'Static method: `Fhqwhgads.again()`', type: 'classMethod' } ], diff --git a/test/fixtures/doc_with_backticks_in_headings.md b/test/fixtures/doc_with_backticks_in_headings.md index 74b4f3fd7ff39d..8b4fe5efaf4d37 100644 --- a/test/fixtures/doc_with_backticks_in_headings.md +++ b/test/fixtures/doc_with_backticks_in_headings.md @@ -8,6 +8,6 @@ ## Constructor: `new Fhqwhgads()` -## Class Method: `Fhqwhgads.again()` +## Static method: `Fhqwhgads.again()` ## `Fqhqwhgads.fullName` diff --git a/test/fixtures/order_of_end_tags_5873.md b/test/fixtures/order_of_end_tags_5873.md index 3eb7dadcb32b1a..888fe231802019 100644 --- a/test/fixtures/order_of_end_tags_5873.md +++ b/test/fixtures/order_of_end_tags_5873.md @@ -2,5 +2,5 @@ ## Subsection -### Class Method: Buffer.from(array) +### Static method: Buffer.from(array) * `array` {Array} diff --git a/tools/doc/json.js b/tools/doc/json.js index bcba923d907fb2..739a4f9f4fd3de 100644 --- a/tools/doc/json.js +++ b/tools/doc/json.js @@ -436,7 +436,7 @@ const r = String.raw; const eventPrefix = '^Event: +'; const classPrefix = '^[Cc]lass: +'; const ctorPrefix = '^(?:[Cc]onstructor: +)?`?new +'; -const classMethodPrefix = '^Class Method: +'; +const classMethodPrefix = '^Static method: +'; const maybeClassPropertyPrefix = '(?:Class Property: +)?'; const maybeQuote = '[\'"]?'; From bd00f266d1c63560e07fa55daaf6ebb64996804b Mon Sep 17 00:00:00 2001 From: Mary Marchini Date: Fri, 7 Aug 2020 12:30:44 -0700 Subject: [PATCH 78/79] meta: uncomment all codeowners A recent feature was added to github-bot to ping codeowners defined on the CODEOWNERS file even if the team doesn't have write permission to the repository. That means we can enable codeowners everywhere in the repository. Ref: https://github.com/nodejs/github-bot/pull/265 Fix: https://github.com/nodejs/node/issues/33984 PR-URL: https://github.com/nodejs/node/pull/34670 Fixes: https://github.com/nodejs/node/issues/33984 Refs: https://github.com/nodejs/github-bot/pull/265 Reviewed-By: James M Snell Reviewed-By: Denys Otrishko Reviewed-By: Matteo Collina --- .github/CODEOWNERS | 98 +++++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2413b5e89f646a..247b5c17b54805 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -5,57 +5,57 @@ # 3. PRs touching any code with a codeowner must be signed off by at least one # person on the code owner team. -./.github/CODEOWNERS @nodejs/tsc +/.github/CODEOWNERS @nodejs/tsc # net -# ./deps/cares @nodejs/net -# ./doc/api/dns.md @nodejs/net -# ./doc/api/dgram.md @nodejs/net -# ./doc/api/net.md @nodejs/net -# ./lib/dgram.js @nodejs/net -# ./lib/dns.js @nodejs/net -# ./lib/net.js @nodejs/net @nodejs/quic -# ./lib/internal/dgram.js @nodejs/net -# ./lib/internal/dns/* @nodejs/net -# ./lib/internal/net.js @nodejs/net -# ./lib/internal/socket_list.js @nodejs/net -# ./lib/internal/js_stream_socket.js @nodejs/net -# ./src/cares_wrap.h @nodejs/net -# ./src/connect_wrap.* @nodejs/net -# ./src/connection_wrap.* @nodejs/net -# ./src/node_sockaddr* @nodejs/net -# ./src/tcp_wrap.* @nodejs/net -# ./src/udp_wrap.* @nodejs/net +/deps/cares @nodejs/net +/doc/api/dns.md @nodejs/net +/doc/api/dgram.md @nodejs/net +/doc/api/net.md @nodejs/net +/lib/dgram.js @nodejs/net +/lib/dns.js @nodejs/net +/lib/net.js @nodejs/net @nodejs/quic +/lib/internal/dgram.js @nodejs/net +/lib/internal/dns/* @nodejs/net +/lib/internal/net.js @nodejs/net +/lib/internal/socket_list.js @nodejs/net +/lib/internal/js_stream_socket.js @nodejs/net +/src/cares_wrap.h @nodejs/net +/src/connect_wrap.* @nodejs/net +/src/connection_wrap.* @nodejs/net +/src/node_sockaddr* @nodejs/net +/src/tcp_wrap.* @nodejs/net +/src/udp_wrap.* @nodejs/net # tls/crypto -# ./lib/internal/crypto/* @nodejs/crypto -# ./lib/internal/tls.js @nodejs/crypto @nodejs/net -# ./lib/crypto.js @nodejs/crypto -# ./lib/tls.js @nodejs/crypto @nodejs/net -# ./src/node_crypto* @nodejs/crypto -# ./src/node_crypto_common* @nodejs/crypto @nodejs/quic +/lib/internal/crypto/* @nodejs/crypto +/lib/internal/tls.js @nodejs/crypto @nodejs/net +/lib/crypto.js @nodejs/crypto +/lib/tls.js @nodejs/crypto @nodejs/net +/src/node_crypto* @nodejs/crypto +/src/node_crypto_common* @nodejs/crypto @nodejs/quic # http -# ./deps/llhttp/* @nodejs/http @nodejs/net -# ./doc/api/http.md @nodejs/http @nodejs/net -# ./doc/api/http2.md @nodejs/http @nodejs/net -# ./lib/_http_* @nodejs/http @nodejs/net -# ./lib/http.js @nodejs/http @nodejs/net -# ./lib/https.js @nodejs/crypto @nodejs/net @nodejs/http -# ./src/node_http_common* @nodejs/http @nodejs/http2 @nodejs/quic @nodejs/net -# ./src/node_http_parser.cc @nodejs/http @nodejs/net +/deps/llhttp/* @nodejs/http @nodejs/net +/doc/api/http.md @nodejs/http @nodejs/net +/doc/api/http2.md @nodejs/http @nodejs/net +/lib/_http_* @nodejs/http @nodejs/net +/lib/http.js @nodejs/http @nodejs/net +/lib/https.js @nodejs/crypto @nodejs/net @nodejs/http +/src/node_http_common* @nodejs/http @nodejs/http2 @nodejs/quic @nodejs/net +/src/node_http_parser.cc @nodejs/http @nodejs/net # http2 -./deps/nghttp2/* @nodejs/http2 @nodejs/net -./doc/api/http2.md @nodejs/http2 @nodejs/net -./lib/http2.js @nodejs/http2 @nodejs/net -./lib/internal/http2/* @nodejs/http2 @nodejs/net -./src/node_http2* @nodejs/http2 @nodejs/net -./src/node_mem* @nodejs/http2 +/deps/nghttp2/* @nodejs/http2 @nodejs/net +/doc/api/http2.md @nodejs/http2 @nodejs/net +/lib/http2.js @nodejs/http2 @nodejs/net +/lib/internal/http2/* @nodejs/http2 @nodejs/net +/src/node_http2* @nodejs/http2 @nodejs/net +/src/node_mem* @nodejs/http2 # quic @@ -68,16 +68,16 @@ # modules -# ./doc/api/modules.md @nodejs/modules -# ./doc/api/esm.md @nodejs/modules -# ./lib/module.js @nodejs/modules -# ./lib/internal/modules/* @nodejs/modules -# ./lib/internal/bootstrap/loaders.js @nodejs/modules -# ./src/module_wrap* @nodejs/modules @nodejs/vm +/doc/api/modules.md @nodejs/modules +/doc/api/esm.md @nodejs/modules +/lib/module.js @nodejs/modules +/lib/internal/modules/* @nodejs/modules +/lib/internal/bootstrap/loaders.js @nodejs/modules +/src/module_wrap* @nodejs/modules @nodejs/vm # N-API -# /src/node_api* @nodejs/n-api -# /src/js_native_api* @nodejs/n-api -# /doc/guides/adding-new-napi-api.md @nodejs/n-api -# /doc/api/n-api.md @nodejs/n-api +/src/node_api* @nodejs/n-api +/src/js_native_api* @nodejs/n-api +/doc/guides/adding-new-napi-api.md @nodejs/n-api +/doc/api/n-api.md @nodejs/n-api From b45ea94c28a9c8d6be866e534a423ded326a4c6c Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Sun, 9 Aug 2020 22:10:24 -0700 Subject: [PATCH 79/79] 2020-08-11, Version 14.8.0 (Current) Notable changes: async_hooks: * (SEMVER-MINOR) add AsyncResource.bind utility (James M Snell) https://github.com/nodejs/node/pull/34574 doc: * add Ricky Zhou to collaborators (rickyes) https://github.com/nodejs/node/pull/34676 * add release key for Ruy Adorno (Ruy Adorno) https://github.com/nodejs/node/pull/34628 * add DerekNonGeneric to collaborators (Derek Lewis) https://github.com/nodejs/node/pull/34602 module: * (SEMVER-MINOR) unflag Top-Level Await (Myles Borins) https://github.com/nodejs/node/pull/34558 n-api: * (SEMVER-MINOR) support type-tagging objects (Gabriel Schulhof) https://github.com/nodejs/node/pull/28237 n-api,src: * (SEMVER-MINOR) provide asynchronous cleanup hooks (Anna Henningsen) https://github.com/nodejs/node/pull/34572 PR-URL: https://github.com/nodejs/node/pull/34704 --- CHANGELOG.md | 3 +- doc/api/addons.md | 2 +- doc/api/async_hooks.md | 4 +- doc/api/n-api.md | 10 ++-- doc/changelogs/CHANGELOG_V14.md | 96 +++++++++++++++++++++++++++++++++ src/node_version.h | 6 +-- 6 files changed, 109 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7f796691c38d1..446edd44508f3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,7 +31,8 @@ release. -14.7.0
+14.8.0
+14.7.0
14.6.0
14.5.0
14.4.0
diff --git a/doc/api/addons.md b/doc/api/addons.md index 36d3922b795bce..e470ee40bc615f 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -234,7 +234,7 @@ NODE_MODULE_INIT(/* exports, module, context */) { #### Worker support diff --git a/doc/api/async_hooks.md b/doc/api/async_hooks.md index 745a2376257ed9..74abab4fa789be 100644 --- a/doc/api/async_hooks.md +++ b/doc/api/async_hooks.md @@ -729,7 +729,7 @@ class DBQuery extends AsyncResource { #### Static method: `AsyncResource.bind(fn[, type])` * `fn` {Function} The function to bind to the current execution context. @@ -743,7 +743,7 @@ the `AsyncResource` to which the function is bound. #### `asyncResource.bind(fn)` * `fn` {Function} The function to bind to the current `AsyncResource`. diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 7689c67b183fe1..92126ed47c74a9 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -602,7 +602,7 @@ For more details, review the [Object lifetime management][]. #### napi_type_tag A 128-bit value stored as two unsigned 64-bit integers. It serves as a UUID @@ -1577,7 +1577,7 @@ with `napi_add_env_cleanup_hook`, otherwise the process will abort. #### napi_add_async_cleanup_hook > Stability: 1 - Experimental @@ -1605,7 +1605,7 @@ is being torn down anyway. #### napi_remove_async_cleanup_hook > Stability: 1 - Experimental @@ -4666,7 +4666,7 @@ JavaScript object becomes garbage-collected. ### napi_type_tag_object > Stability: 1 - Experimental @@ -4693,7 +4693,7 @@ If the object already has an associated type tag, this API will return ### napi_check_object_type_tag > Stability: 1 - Experimental diff --git a/doc/changelogs/CHANGELOG_V14.md b/doc/changelogs/CHANGELOG_V14.md index 9df37eb9ad3ec2..dc30920df2c631 100644 --- a/doc/changelogs/CHANGELOG_V14.md +++ b/doc/changelogs/CHANGELOG_V14.md @@ -10,6 +10,7 @@ +14.8.0
14.7.0
14.6.0
14.5.0
@@ -38,6 +39,101 @@ * [io.js](CHANGELOG_IOJS.md) * [Archive](CHANGELOG_ARCHIVE.md) + +## 2020-08-11, Version 14.8.0 (Current), @codebytere + +### Notable Changes + +* [[`16aa927216`](https://github.com/nodejs/node/commit/16aa927216)] - **(SEMVER-MINOR)** **async_hooks**: add AsyncResource.bind utility (James M Snell) [#34574](https://github.com/nodejs/node/pull/34574) +* [[`dc49561e8d`](https://github.com/nodejs/node/commit/dc49561e8d)] - **deps**: update to uvwasi 0.0.10 (Colin Ihrig) [#34623](https://github.com/nodejs/node/pull/34623) +* [[`6cd1c41604`](https://github.com/nodejs/node/commit/6cd1c41604)] - **doc**: add Ricky Zhou to collaborators (rickyes) [#34676](https://github.com/nodejs/node/pull/34676) +* [[`f0a41b2530`](https://github.com/nodejs/node/commit/f0a41b2530)] - **doc**: add release key for Ruy Adorno (Ruy Adorno) [#34628](https://github.com/nodejs/node/pull/34628) +* [[`10dd7a0eda`](https://github.com/nodejs/node/commit/10dd7a0eda)] - **doc**: add DerekNonGeneric to collaborators (Derek Lewis) [#34602](https://github.com/nodejs/node/pull/34602) +* [[`62bb2e757f`](https://github.com/nodejs/node/commit/62bb2e757f)] - **(SEMVER-MINOR)** **module**: unflag Top-Level Await (Myles Borins) [#34558](https://github.com/nodejs/node/pull/34558) +* [[`8cc9e5eb52`](https://github.com/nodejs/node/commit/8cc9e5eb52)] - **(SEMVER-MINOR)** **n-api**: support type-tagging objects (Gabriel Schulhof) [#28237](https://github.com/nodejs/node/pull/28237) +* [[`e89ec46ba9`](https://github.com/nodejs/node/commit/e89ec46ba9)] - **(SEMVER-MINOR)** **n-api,src**: provide asynchronous cleanup hooks (Anna Henningsen) [#34572](https://github.com/nodejs/node/pull/34572) + +### Commits + +* [[`650248922b`](https://github.com/nodejs/node/commit/650248922b)] - **async_hooks**: avoid GC tracking of AsyncResource in ALS (Gerhard Stoebich) [#34653](https://github.com/nodejs/node/pull/34653) +* [[`0a51aa8fdb`](https://github.com/nodejs/node/commit/0a51aa8fdb)] - **async_hooks**: avoid unneeded AsyncResource creation (Gerhard Stoebich) [#34616](https://github.com/nodejs/node/pull/34616) +* [[`0af9bee4c3`](https://github.com/nodejs/node/commit/0af9bee4c3)] - **async_hooks**: improve property descriptors in als.bind (Gerhard Stoebich) [#34620](https://github.com/nodejs/node/pull/34620) +* [[`16aa927216`](https://github.com/nodejs/node/commit/16aa927216)] - **(SEMVER-MINOR)** **async_hooks**: add AsyncResource.bind utility (James M Snell) [#34574](https://github.com/nodejs/node/pull/34574) +* [[`e45c68af27`](https://github.com/nodejs/node/commit/e45c68af27)] - **async_hooks**: don't read resource if ALS is disabled (Gerhard Stoebich) [#34617](https://github.com/nodejs/node/pull/34617) +* [[`e9aebc3a8f`](https://github.com/nodejs/node/commit/e9aebc3a8f)] - **async_hooks**: fix id assignment in fast-path promise hook (Andrey Pechkurov) [#34548](https://github.com/nodejs/node/pull/34548) +* [[`5aed83c77f`](https://github.com/nodejs/node/commit/5aed83c77f)] - **async_hooks**: fix resource stack for deep stacks (Anna Henningsen) [#34573](https://github.com/nodejs/node/pull/34573) +* [[`9af62641c6`](https://github.com/nodejs/node/commit/9af62641c6)] - **async_hooks**: execute destroy hooks earlier (Gerhard Stoebich) [#34342](https://github.com/nodejs/node/pull/34342) +* [[`14656e1703`](https://github.com/nodejs/node/commit/14656e1703)] - **async_hooks**: don't reuse resource in HttpAgent when queued (Andrey Pechkurov) [#34439](https://github.com/nodejs/node/pull/34439) +* [[`c4457d873f`](https://github.com/nodejs/node/commit/c4457d873f)] - **benchmark**: always throw the same Error instance (Anna Henningsen) [#34523](https://github.com/nodejs/node/pull/34523) +* [[`6a129d0cf5`](https://github.com/nodejs/node/commit/6a129d0cf5)] - **build**: do not run auto-start-ci on forks (Evan Lucas) [#34650](https://github.com/nodejs/node/pull/34650) +* [[`2cd299b217`](https://github.com/nodejs/node/commit/2cd299b217)] - **build**: run CI on release branches (Shelley Vohr) [#34649](https://github.com/nodejs/node/pull/34649) +* [[`9ed9ccc5b3`](https://github.com/nodejs/node/commit/9ed9ccc5b3)] - **build**: enable build for node-v8 push (gengjiawen) [#34634](https://github.com/nodejs/node/pull/34634) +* [[`10f29e7550`](https://github.com/nodejs/node/commit/10f29e7550)] - **build**: increase startCI verbosity and fix job name (Mary Marchini) [#34635](https://github.com/nodejs/node/pull/34635) +* [[`befbaf384e`](https://github.com/nodejs/node/commit/befbaf384e)] - **build**: don't run auto-start-ci on push (Mary Marchini) [#34588](https://github.com/nodejs/node/pull/34588) +* [[`4af5dbd3bf`](https://github.com/nodejs/node/commit/4af5dbd3bf)] - **build**: fix auto-start-ci script path (Mary Marchini) [#34588](https://github.com/nodejs/node/pull/34588) +* [[`70cf3cbdfa`](https://github.com/nodejs/node/commit/70cf3cbdfa)] - **build**: auto start Jenkins CI via PR labels (Mary Marchini) [#34089](https://github.com/nodejs/node/pull/34089) +* [[`70e9eceeee`](https://github.com/nodejs/node/commit/70e9eceeee)] - **build**: toolchain.gypi and node\_gyp.py cleanup (iandrc) [#34268](https://github.com/nodejs/node/pull/34268) +* [[`465968c5f8`](https://github.com/nodejs/node/commit/465968c5f8)] - **console**: document the behavior of console.assert() (iandrc) [#34501](https://github.com/nodejs/node/pull/34501) +* [[`a7b4318df9`](https://github.com/nodejs/node/commit/a7b4318df9)] - **crypto**: add OP flag constants added in OpenSSL v1.1.1 (Mateusz Krawczuk) [#33929](https://github.com/nodejs/node/pull/33929) +* [[`dc49561e8d`](https://github.com/nodejs/node/commit/dc49561e8d)] - **deps**: update to uvwasi 0.0.10 (Colin Ihrig) [#34623](https://github.com/nodejs/node/pull/34623) +* [[`8b1ec43da4`](https://github.com/nodejs/node/commit/8b1ec43da4)] - **doc**: use \_Static method\_ instead of \_Class Method\_ (Rich Trott) [#34659](https://github.com/nodejs/node/pull/34659) +* [[`a1b9d7f42e`](https://github.com/nodejs/node/commit/a1b9d7f42e)] - **doc**: tidy some addons.md text (Rich Trott) [#34654](https://github.com/nodejs/node/pull/34654) +* [[`b78278b922`](https://github.com/nodejs/node/commit/b78278b922)] - **doc**: use \_Class Method\_ in async\_hooks.md (Rich Trott) [#34626](https://github.com/nodejs/node/pull/34626) +* [[`6cd1c41604`](https://github.com/nodejs/node/commit/6cd1c41604)] - **doc**: add Ricky Zhou to collaborators (rickyes) [#34676](https://github.com/nodejs/node/pull/34676) +* [[`d8e0deaa7c`](https://github.com/nodejs/node/commit/d8e0deaa7c)] - **doc**: edit process.title note for brevity and clarity (Rich Trott) [#34627](https://github.com/nodejs/node/pull/34627) +* [[`dd6bf20e8f`](https://github.com/nodejs/node/commit/dd6bf20e8f)] - **doc**: update fs.watch() availability for IBM i (iandrc) [#34611](https://github.com/nodejs/node/pull/34611) +* [[`f260bdd57b`](https://github.com/nodejs/node/commit/f260bdd57b)] - **doc**: fix typo in path.md (aetheryx) [#34550](https://github.com/nodejs/node/pull/34550) +* [[`f0a41b2530`](https://github.com/nodejs/node/commit/f0a41b2530)] - **doc**: add release key for Ruy Adorno (Ruy Adorno) [#34628](https://github.com/nodejs/node/pull/34628) +* [[`3f55dcd723`](https://github.com/nodejs/node/commit/3f55dcd723)] - **doc**: clarify process.title inconsistencies (Corey Butler) [#34557](https://github.com/nodejs/node/pull/34557) +* [[`6cd9ea82f6`](https://github.com/nodejs/node/commit/6cd9ea82f6)] - **doc**: document the connection event for HTTP2 & TLS servers (Tim Perry) [#34531](https://github.com/nodejs/node/pull/34531) +* [[`0a9389bb1a`](https://github.com/nodejs/node/commit/0a9389bb1a)] - **doc**: mention null special-case for `napi\_typeof` (Renée Kooi) [#34577](https://github.com/nodejs/node/pull/34577) +* [[`10dd7a0eda`](https://github.com/nodejs/node/commit/10dd7a0eda)] - **doc**: add DerekNonGeneric to collaborators (Derek Lewis) [#34602](https://github.com/nodejs/node/pull/34602) +* [[`d7eaf3a027`](https://github.com/nodejs/node/commit/d7eaf3a027)] - **doc**: revise N-API versions matrix text (Rich Trott) [#34566](https://github.com/nodejs/node/pull/34566) +* [[`e2bea73b03`](https://github.com/nodejs/node/commit/e2bea73b03)] - **doc**: clarify N-API version 1 (Michael Dawson) [#34344](https://github.com/nodejs/node/pull/34344) +* [[`be23e23361`](https://github.com/nodejs/node/commit/be23e23361)] - **doc**: use consistent spelling for "falsy" (Rich Trott) [#34545](https://github.com/nodejs/node/pull/34545) +* [[`f393ae9296`](https://github.com/nodejs/node/commit/f393ae9296)] - **doc**: simplify and clarify console.assert() documentation (Rich Trott) [#34544](https://github.com/nodejs/node/pull/34544) +* [[`b69ff2ff60`](https://github.com/nodejs/node/commit/b69ff2ff60)] - **doc**: use consistent capitalization for addons (Rich Trott) [#34536](https://github.com/nodejs/node/pull/34536) +* [[`212d17fa06`](https://github.com/nodejs/node/commit/212d17fa06)] - **doc**: add mmarchini pronouns (Mary Marchini) [#34586](https://github.com/nodejs/node/pull/34586) +* [[`7a28c3d543`](https://github.com/nodejs/node/commit/7a28c3d543)] - **doc**: update mmarchini contact info (Mary Marchini) [#34586](https://github.com/nodejs/node/pull/34586) +* [[`c8104f3d10`](https://github.com/nodejs/node/commit/c8104f3d10)] - **doc**: update .mailmap for mmarchini (Mary Marchini) [#34586](https://github.com/nodejs/node/pull/34586) +* [[`692a735881`](https://github.com/nodejs/node/commit/692a735881)] - **doc**: use sentence-case for headers in SECURITY.md (Rich Trott) [#34525](https://github.com/nodejs/node/pull/34525) +* [[`44e6c010b4`](https://github.com/nodejs/node/commit/44e6c010b4)] - **esm**: fix hook mistypes and links to types (Derek Lewis) [#34240](https://github.com/nodejs/node/pull/34240) +* [[`7322e58d11`](https://github.com/nodejs/node/commit/7322e58d11)] - **http**: reset headers timeout on headers complete (Robert Nagy) [#34578](https://github.com/nodejs/node/pull/34578) +* [[`36fd3daae6`](https://github.com/nodejs/node/commit/36fd3daae6)] - **http**: provide keep-alive timeout response header (Robert Nagy) [#34561](https://github.com/nodejs/node/pull/34561) +* [[`d0efaf2fe3`](https://github.com/nodejs/node/commit/d0efaf2fe3)] - **lib**: use non-symbols in isURLInstance check (Shelley Vohr) [#34622](https://github.com/nodejs/node/pull/34622) +* [[`335cb0d1d1`](https://github.com/nodejs/node/commit/335cb0d1d1)] - **lib**: absorb `path` error cases (Gireesh Punathil) [#34519](https://github.com/nodejs/node/pull/34519) +* [[`521e620533`](https://github.com/nodejs/node/commit/521e620533)] - **meta**: uncomment all codeowners (Mary Marchini) [#34670](https://github.com/nodejs/node/pull/34670) +* [[`650adeca22`](https://github.com/nodejs/node/commit/650adeca22)] - **meta**: enable http2 team for CODEOWNERS (Rich Trott) [#34534](https://github.com/nodejs/node/pull/34534) +* [[`35ef9907aa`](https://github.com/nodejs/node/commit/35ef9907aa)] - **module**: handle Top-Level Await non-fulfills better (Anna Henningsen) [#34640](https://github.com/nodejs/node/pull/34640) +* [[`62bb2e757f`](https://github.com/nodejs/node/commit/62bb2e757f)] - **(SEMVER-MINOR)** **module**: unflag Top-Level Await (Myles Borins) [#34558](https://github.com/nodejs/node/pull/34558) +* [[`fbd411d28a`](https://github.com/nodejs/node/commit/fbd411d28a)] - **n-api**: fix use-after-free with napi\_remove\_async\_cleanup\_hook (Anna Henningsen) [#34662](https://github.com/nodejs/node/pull/34662) +* [[`8cc9e5eb52`](https://github.com/nodejs/node/commit/8cc9e5eb52)] - **(SEMVER-MINOR)** **n-api**: support type-tagging objects (Gabriel Schulhof) [#28237](https://github.com/nodejs/node/pull/28237) +* [[`2703fe498e`](https://github.com/nodejs/node/commit/2703fe498e)] - **n-api**: simplify bigint-from-word creation (Gabriel Schulhof) [#34554](https://github.com/nodejs/node/pull/34554) +* [[`e89ec46ba9`](https://github.com/nodejs/node/commit/e89ec46ba9)] - **(SEMVER-MINOR)** **n-api,src**: provide asynchronous cleanup hooks (Anna Henningsen) [#34572](https://github.com/nodejs/node/pull/34572) +* [[`b1890e0866`](https://github.com/nodejs/node/commit/b1890e0866)] - **net**: don't return the stream object from onStreamRead (Robey Pointer) [#34375](https://github.com/nodejs/node/pull/34375) +* [[`35fdfb44a2`](https://github.com/nodejs/node/commit/35fdfb44a2)] - **policy**: increase tests via permutation matrix (Bradley Meck) [#34404](https://github.com/nodejs/node/pull/34404) +* [[`ddd339ff45`](https://github.com/nodejs/node/commit/ddd339ff45)] - **repl**: use \_Node.js\_ in user-facing REPL text (Rich Trott) [#34644](https://github.com/nodejs/node/pull/34644) +* [[`276e2980e2`](https://github.com/nodejs/node/commit/276e2980e2)] - **repl**: use \_REPL\_ in user-facing text (Rich Trott) [#34643](https://github.com/nodejs/node/pull/34643) +* [[`465c262ac6`](https://github.com/nodejs/node/commit/465c262ac6)] - **repl**: improve static import error message in repl (Myles Borins) [#33588](https://github.com/nodejs/node/pull/33588) +* [[`12cb0fb8a0`](https://github.com/nodejs/node/commit/12cb0fb8a0)] - **repl**: give repl entries unique names (Bradley Meck) [#34372](https://github.com/nodejs/node/pull/34372) +* [[`2dbd15a075`](https://github.com/nodejs/node/commit/2dbd15a075)] - **src**: fix linter failures (Anna Henningsen) [#34582](https://github.com/nodejs/node/pull/34582) +* [[`2761f349ec`](https://github.com/nodejs/node/commit/2761f349ec)] - **src**: spin shutdown loop while immediates are pending (Anna Henningsen) [#34662](https://github.com/nodejs/node/pull/34662) +* [[`39ca48c840`](https://github.com/nodejs/node/commit/39ca48c840)] - **src**: fix `size` underflow in CallbackQueue (Anna Henningsen) [#34662](https://github.com/nodejs/node/pull/34662) +* [[`c1abc8d3e5`](https://github.com/nodejs/node/commit/c1abc8d3e5)] - **src**: fix unused namespace member in node\_util (Andrey Pechkurov) [#34565](https://github.com/nodejs/node/pull/34565) +* [[`e146686972`](https://github.com/nodejs/node/commit/e146686972)] - **test**: fix wrong method call (gengjiawen) [#34629](https://github.com/nodejs/node/pull/34629) +* [[`ca89c375f7`](https://github.com/nodejs/node/commit/ca89c375f7)] - **test**: add debugging for callbacks in test-https-foafssl.js (Rich Trott) [#34603](https://github.com/nodejs/node/pull/34603) +* [[`2133b18bee`](https://github.com/nodejs/node/commit/2133b18bee)] - **test**: add debugging for test-https-foafssl.js (Rich Trott) [#34603](https://github.com/nodejs/node/pull/34603) +* [[`b9fb0c63b3`](https://github.com/nodejs/node/commit/b9fb0c63b3)] - **test**: convert most N-API tests from C++ to C (Gabriel Schulhof) [#34615](https://github.com/nodejs/node/pull/34615) +* [[`54a4c6a39c`](https://github.com/nodejs/node/commit/54a4c6a39c)] - **test**: replace flaky pummel regression tests (Anna Henningsen) [#34530](https://github.com/nodejs/node/pull/34530) +* [[`bd55236788`](https://github.com/nodejs/node/commit/bd55236788)] - **test**: change Fixes: to Refs: (Rich Trott) [#34568](https://github.com/nodejs/node/pull/34568) +* [[`a340587cfd`](https://github.com/nodejs/node/commit/a340587cfd)] - **test**: fix flaky http-parser-timeout-reset (Robert Nagy) [#34609](https://github.com/nodejs/node/pull/34609) +* [[`9c442f9786`](https://github.com/nodejs/node/commit/9c442f9786)] - **test**: remove unneeded flag check in test-vm-memleak (Rich Trott) [#34528](https://github.com/nodejs/node/pull/34528) +* [[`05100e1eec`](https://github.com/nodejs/node/commit/05100e1eec)] - **tools**: fix C++ import checker argument expansion (Anna Henningsen) [#34582](https://github.com/nodejs/node/pull/34582) +* [[`bf6c8aaae3`](https://github.com/nodejs/node/commit/bf6c8aaae3)] - **tools**: update ESLint to 7.6.0 (Colin Ihrig) [#34589](https://github.com/nodejs/node/pull/34589) +* [[`0b1616c2f0`](https://github.com/nodejs/node/commit/0b1616c2f0)] - **tools**: add meta.fixable to fixable lint rules (Colin Ihrig) [#34589](https://github.com/nodejs/node/pull/34589) +* [[`f46649bc5b`](https://github.com/nodejs/node/commit/f46649bc5b)] - **util**: print External address from inspect (unknown) [#34398](https://github.com/nodejs/node/pull/34398) +* [[`2fa24c0ccc`](https://github.com/nodejs/node/commit/2fa24c0ccc)] - **wasi**: add \_\_wasi\_fd\_filestat\_set\_times() test (Colin Ihrig) [#34623](https://github.com/nodejs/node/pull/34623) + ## 2020-07-29, Version 14.7.0 (Current), @MylesBorins prepared by @ruyadorno diff --git a/src/node_version.h b/src/node_version.h index 38be0bb7120cfd..b7f38a2c037b84 100644 --- a/src/node_version.h +++ b/src/node_version.h @@ -23,13 +23,13 @@ #define SRC_NODE_VERSION_H_ #define NODE_MAJOR_VERSION 14 -#define NODE_MINOR_VERSION 7 -#define NODE_PATCH_VERSION 1 +#define NODE_MINOR_VERSION 8 +#define NODE_PATCH_VERSION 0 #define NODE_VERSION_IS_LTS 0 #define NODE_VERSION_LTS_CODENAME "" -#define NODE_VERSION_IS_RELEASE 0 +#define NODE_VERSION_IS_RELEASE 1 #ifndef NODE_STRINGIFY #define NODE_STRINGIFY(n) NODE_STRINGIFY_HELPER(n)