From 04df3daa3f9e97e11c0a604856f88c74589cdf63 Mon Sep 17 00:00:00 2001
From: Anna Henningsen <anna@addaleax.net>
Date: Tue, 14 Jul 2020 17:21:03 +0200
Subject: [PATCH 01/10] src: do not crash if ToggleAsyncHook fails during
 termination
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

In the termination case, we should not crash. There’s also no harm
being done by ignoring the termination exception here, since the
thread is about to be torn down anyway.

Also, add a guard against running this during shutdown. That is the
likely cause of https://github.com/nodejs/node/issues/34361.

Fixes: https://github.com/nodejs/node/issues/34361

PR-URL: https://github.com/nodejs/node/pull/34362
Fixes: https://github.com/nodejs/node/issues/27261
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
---
 src/inspector_agent.cc | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc
index 7712a62d7cbeb0..54849014a90dd4 100644
--- a/src/inspector_agent.cc
+++ b/src/inspector_agent.cc
@@ -928,13 +928,18 @@ void Agent::DisableAsyncHook() {
 
 void Agent::ToggleAsyncHook(Isolate* isolate,
                             const Global<Function>& fn) {
+  // Guard against running this during cleanup -- no async events will be
+  // emitted anyway at that point anymore, and calling into JS is not possible.
+  // This should probably not be something we're attempting in the first place,
+  // Refs: https://github.com/nodejs/node/pull/34362#discussion_r456006039
+  if (!parent_env_->can_call_into_js()) return;
   CHECK(parent_env_->has_run_bootstrapping_code());
   HandleScope handle_scope(isolate);
   CHECK(!fn.IsEmpty());
   auto context = parent_env_->context();
   v8::TryCatch try_catch(isolate);
   USE(fn.Get(isolate)->Call(context, Undefined(isolate), 0, nullptr));
-  if (try_catch.HasCaught()) {
+  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
     PrintCaughtException(isolate, context, try_catch);
     FatalError("\nnode::inspector::Agent::ToggleAsyncHook",
                "Cannot toggle Inspector's AsyncHook, please report this.");

From 078ee99b6b03820cff987a538e93fe1486c8bec6 Mon Sep 17 00:00:00 2001
From: ConorDavenport <cnrdavenport@gmail.com>
Date: Thu, 27 Feb 2020 11:41:05 +0000
Subject: [PATCH 02/10] assert: port common.mustCall() to assert

Fixes: https://github.com/nodejs/node/issues/31392

PR-URL: https://github.com/nodejs/node/pull/31982
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Zeyu Yang <himself65@outlook.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
---
 doc/api/assert.md                             | 135 ++++++++++++++++++
 doc/api/errors.md                             |   7 +
 lib/assert.js                                 |   3 +
 lib/internal/assert/assertion_error.js        |  20 ++-
 lib/internal/assert/calltracker.js            |  93 ++++++++++++
 lib/internal/errors.js                        |   2 +
 node.gyp                                      |   1 +
 .../parallel/test-assert-calltracker-calls.js |  66 +++++++++
 .../test-assert-calltracker-report.js         |  32 +++++
 .../test-assert-calltracker-verify.js         |  32 +++++
 10 files changed, 388 insertions(+), 3 deletions(-)
 create mode 100644 lib/internal/assert/calltracker.js
 create mode 100644 test/parallel/test-assert-calltracker-calls.js
 create mode 100644 test/parallel/test-assert-calltracker-report.js
 create mode 100644 test/parallel/test-assert-calltracker-verify.js

diff --git a/doc/api/assert.md b/doc/api/assert.md
index 61572f2bd05f9f..c027df2497f15c 100644
--- a/doc/api/assert.md
+++ b/doc/api/assert.md
@@ -147,6 +147,137 @@ try {
 }
 ```
 
+## Class: `assert.CallTracker`
+
+### `new assert.CallTracker()`
+<!-- YAML
+added: REPLACEME
+-->
+
+Creates a new [`CallTracker`][] object which can be used to track if functions
+were called a specific number of times. The `tracker.verify()` must be called
+for the verification to take place. The usual pattern would be to call it in a
+[`process.on('exit')`][] handler.
+
+```js
+const assert = require('assert');
+
+const tracker = new assert.CallTracker();
+
+function func() {}
+
+// callsfunc() must be called exactly 1 time before tracker.verify().
+const callsfunc = tracker.calls(func, 1);
+
+callsfunc();
+
+// Calls tracker.verify() and verifies if all tracker.calls() functions have
+// been called exact times.
+process.on('exit', () => {
+  tracker.verify();
+});
+```
+
+### `tracker.calls([fn][, exact])`
+<!-- YAML
+added: REPLACEME
+-->
+
+* `fn` {Function} **Default** A no-op function.
+* `exact` {number} **Default** `1`.
+* Returns: {Function} that wraps `fn`.
+
+The wrapper function is expected to be called exactly `exact` times. If the
+function has not been called exactly `exact` times when
+[`tracker.verify()`][] is called, then [`tracker.verify()`][] will throw an
+error.
+
+```js
+const assert = require('assert');
+
+// Creates call tracker.
+const tracker = new assert.CallTracker();
+
+function func() {}
+
+// Returns a function that wraps func() that must be called exact times
+// before tracker.verify().
+const callsfunc = tracker.calls(func);
+```
+
+### `tracker.report()`
+<!-- YAML
+added: REPLACEME
+-->
+
+* Returns: {Array} of objects containing information about the wrapper functions
+returned by [`tracker.calls()`][].
+* Object {Object}
+  * `message` {string}
+  * `actual` {number} The actual number of times the function was called.
+  * `expected` {number} The number of times the function was expected to be
+    called.
+  * `operator` {string} The name of the function that is wrapped.
+  * `stack` {Object} A stack trace of the function.
+
+The arrays contains information about the expected and actual number of calls of
+the functions that have not been called the expected number of times.
+
+```js
+const assert = require('assert');
+
+// Creates call tracker.
+const tracker = new assert.CallTracker();
+
+function func() {}
+
+function foo() {}
+
+// Returns a function that wraps func() that must be called exact times
+// before tracker.verify().
+const callsfunc = tracker.calls(func, 2);
+
+// Returns an array containing information on callsfunc()
+tracker.report();
+// [
+//  {
+//    message: 'Expected the func function to be executed 2 time(s) but was
+//    executed 0 time(s).',
+//    actual: 0,
+//    expected: 2,
+//    operator: 'func',
+//    stack: stack trace
+//  }
+// ]
+```
+
+### `tracker.verify()`
+<!-- YAML
+added: REPLACEME
+-->
+
+Iterates through the list of functions passed to
+[`tracker.calls()`][] and will throw an error for functions that
+have not been called the expected number of times.
+
+```js
+const assert = require('assert');
+
+// Creates call tracker.
+const tracker = new assert.CallTracker();
+
+function func() {}
+
+// Returns a function that wraps func() that must be called exact times
+// before tracker.verify().
+const callsfunc = tracker.calls(func, 2);
+
+callsfunc();
+
+// Will throw an error since callsfunc() was only called once.
+tracker.verify();
+```
+
 ## `assert(value[, message])`
 <!-- YAML
 added: v0.5.9
@@ -1400,6 +1531,7 @@ argument.
 [`TypeError`]: errors.html#errors_class_typeerror
 [`WeakMap`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
 [`WeakSet`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet
+[`CallTracker`]: #assert_class_assert_calltracker
 [`assert.deepEqual()`]: #assert_assert_deepequal_actual_expected_message
 [`assert.deepStrictEqual()`]: #assert_assert_deepstrictequal_actual_expected_message
 [`assert.doesNotThrow()`]: #assert_assert_doesnotthrow_fn_error_message
@@ -1411,6 +1543,9 @@ argument.
 [`assert.ok()`]: #assert_assert_ok_value_message
 [`assert.strictEqual()`]: #assert_assert_strictequal_actual_expected_message
 [`assert.throws()`]: #assert_assert_throws_fn_error_message
+[`process.on('exit')`]: process.html#process_event_exit
+[`tracker.calls()`]: #assert_class_assert_CallTracker#tracker_calls
+[`tracker.verify()`]: #assert_class_assert_CallTracker#tracker_verify
 [strict assertion mode]: #assert_strict_assertion_mode
 [Abstract Equality Comparison]: https://tc39.github.io/ecma262/#sec-abstract-equality-comparison
 [Object wrappers]: https://developer.mozilla.org/en-US/docs/Glossary/Primitive#Primitive_wrapper_objects_in_JavaScript
diff --git a/doc/api/errors.md b/doc/api/errors.md
index 672f8d20b2fb94..6901f02ea60280 100644
--- a/doc/api/errors.md
+++ b/doc/api/errors.md
@@ -1972,6 +1972,12 @@ A `Transform` stream finished with data still in the write buffer.
 
 The initialization of a TTY failed due to a system error.
 
+<a id="ERR_UNAVAILABLE_DURING_EXIT"></a>
+### `ERR_UNAVAILABLE_DURING_EXIT`
+
+Function was called within a [`process.on('exit')`][] handler that shouldn't be
+called within [`process.on('exit')`][] handler.
+
 <a id="ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET"></a>
 ### `ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET`
 
@@ -2552,6 +2558,7 @@ such as `process.stdout.on('data')`.
 [`net`]: net.html
 [`new URL(input)`]: url.html#url_constructor_new_url_input_base
 [`new URLSearchParams(iterable)`]: url.html#url_constructor_new_urlsearchparams_iterable
+[`process.on('exit')`]: process.html#Event:-`'exit'`
 [`process.send()`]: process.html#process_process_send_message_sendhandle_options_callback
 [`process.setUncaughtExceptionCaptureCallback()`]: process.html#process_process_setuncaughtexceptioncapturecallback_fn
 [`readable._read()`]: stream.html#stream_readable_read_size_1
diff --git a/lib/assert.js b/lib/assert.js
index f37166be9c6798..6d6afdf8537bbb 100644
--- a/lib/assert.js
+++ b/lib/assert.js
@@ -49,6 +49,7 @@ const { EOL } = require('internal/constants');
 const { NativeModule } = require('internal/bootstrap/loaders');
 
 const errorCache = new Map();
+const CallTracker = require('internal/assert/calltracker');
 
 let isDeepEqual;
 let isDeepStrictEqual;
@@ -900,6 +901,8 @@ assert.doesNotMatch = function doesNotMatch(string, regexp, message) {
   internalMatch(string, regexp, message, doesNotMatch);
 };
 
+assert.CallTracker = CallTracker;
+
 // Expose a strict only variant of assert
 function strict(...args) {
   innerOk(strict, args.length, ...args);
diff --git a/lib/internal/assert/assertion_error.js b/lib/internal/assert/assertion_error.js
index 691f057ad281e3..3c2150c69e4e09 100644
--- a/lib/internal/assert/assertion_error.js
+++ b/lib/internal/assert/assertion_error.js
@@ -312,6 +312,7 @@ class AssertionError extends Error {
       message,
       operator,
       stackStartFn,
+      details,
       // Compatibility with older versions.
       stackStartFunction
     } = options;
@@ -426,9 +427,22 @@ class AssertionError extends Error {
       configurable: true
     });
     this.code = 'ERR_ASSERTION';
-    this.actual = actual;
-    this.expected = expected;
-    this.operator = operator;
+    if (details) {
+      this.actual = undefined;
+      this.expected = undefined;
+      this.operator = undefined;
+      for (let i = 0; i < details.length; i++) {
+        this['message ' + i] = details[i].message;
+        this['actual ' + i] = details[i].actual;
+        this['expected ' + i] = details[i].expected;
+        this['operator ' + i] = details[i].operator;
+        this['stack trace ' + i] = details[i].stack;
+      }
+    } else {
+      this.actual = actual;
+      this.expected = expected;
+      this.operator = operator;
+    }
     // eslint-disable-next-line no-restricted-syntax
     Error.captureStackTrace(this, stackStartFn || stackStartFunction);
     // Create error message including the error code in the name.
diff --git a/lib/internal/assert/calltracker.js b/lib/internal/assert/calltracker.js
new file mode 100644
index 00000000000000..74f517f3f9e99b
--- /dev/null
+++ b/lib/internal/assert/calltracker.js
@@ -0,0 +1,93 @@
+'use strict';
+
+const {
+  Error,
+  SafeSet,
+} = primordials;
+
+const {
+  codes: {
+    ERR_UNAVAILABLE_DURING_EXIT,
+  },
+} = require('internal/errors');
+const AssertionError = require('internal/assert/assertion_error');
+const {
+  validateUint32,
+} = require('internal/validators');
+
+const noop = () => {};
+
+class CallTracker {
+
+  #callChecks = new SafeSet()
+
+  calls(fn, exact = 1) {
+    if (process._exiting)
+      throw new ERR_UNAVAILABLE_DURING_EXIT();
+    if (typeof fn === 'number') {
+      exact = fn;
+      fn = noop;
+    } else if (fn === undefined) {
+      fn = noop;
+    }
+
+    validateUint32(exact, 'exact', true);
+
+    const context = {
+      exact,
+      actual: 0,
+      // eslint-disable-next-line no-restricted-syntax
+      stackTrace: new Error(),
+      name: fn.name || 'calls'
+    };
+    const callChecks = this.#callChecks;
+    callChecks.add(context);
+
+    return function() {
+      context.actual++;
+      if (context.actual === context.exact) {
+        // Once function has reached its call count remove it from
+        // callChecks set to prevent memory leaks.
+        callChecks.delete(context);
+      }
+      // If function has been called more than expected times, add back into
+      // callchecks.
+      if (context.actual === context.exact + 1) {
+        callChecks.add(context);
+      }
+      return fn.apply(this, arguments);
+    };
+  }
+
+  report() {
+    const errors = [];
+    for (const context of this.#callChecks) {
+      // If functions have not been called exact times
+      if (context.actual !== context.exact) {
+        const message = `Expected the ${context.name} function to be ` +
+                        `executed ${context.exact} time(s) but was ` +
+                        `executed ${context.actual} time(s).`;
+        errors.push({
+          message,
+          actual: context.actual,
+          expected: context.exact,
+          operator: context.name,
+          stack: context.stackTrace
+        });
+      }
+    }
+    return errors;
+  }
+
+  verify() {
+    const errors = this.report();
+    if (errors.length > 0) {
+      throw new AssertionError({
+        message: 'Function(s) were not called the expected number of times',
+        details: errors,
+      });
+    }
+  }
+}
+
+module.exports = CallTracker;
diff --git a/lib/internal/errors.js b/lib/internal/errors.js
index a3d99a79c6340c..754ecff1b979c7 100644
--- a/lib/internal/errors.js
+++ b/lib/internal/errors.js
@@ -1397,6 +1397,8 @@ E('ERR_TRANSFORM_ALREADY_TRANSFORMING',
 E('ERR_TRANSFORM_WITH_LENGTH_0',
   'Calling transform done when writableState.length != 0', Error);
 E('ERR_TTY_INIT_FAILED', 'TTY initialization failed', SystemError);
+E('ERR_UNAVAILABLE_DURING_EXIT', 'Cannot call function in process exit ' +
+  'handler', Error);
 E('ERR_UNCAUGHT_EXCEPTION_CAPTURE_ALREADY_SET',
   '`process.setupUncaughtExceptionCapture()` was called while a capture ' +
     'callback was already active',
diff --git a/node.gyp b/node.gyp
index b030de8364a429..ce4fd8918ba0bc 100644
--- a/node.gyp
+++ b/node.gyp
@@ -94,6 +94,7 @@
       'lib/zlib.js',
       'lib/internal/assert.js',
       'lib/internal/assert/assertion_error.js',
+      'lib/internal/assert/calltracker.js',
       'lib/internal/async_hooks.js',
       'lib/internal/buffer.js',
       'lib/internal/cli_table.js',
diff --git a/test/parallel/test-assert-calltracker-calls.js b/test/parallel/test-assert-calltracker-calls.js
new file mode 100644
index 00000000000000..4de23d4658468a
--- /dev/null
+++ b/test/parallel/test-assert-calltracker-calls.js
@@ -0,0 +1,66 @@
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// This test ensures that assert.CallTracker.calls() works as intended.
+
+const tracker = new assert.CallTracker();
+
+function bar() {}
+
+const err = {
+  code: 'ERR_INVALID_ARG_TYPE',
+};
+
+// Ensures calls() throws on invalid input types.
+assert.throws(() => {
+  const callsbar = tracker.calls(bar, '1');
+  callsbar();
+}, err
+);
+
+assert.throws(() => {
+  const callsbar = tracker.calls(bar, 0.1);
+  callsbar();
+}, { code: 'ERR_OUT_OF_RANGE' }
+);
+
+assert.throws(() => {
+  const callsbar = tracker.calls(bar, true);
+  callsbar();
+}, err
+);
+
+assert.throws(() => {
+  const callsbar = tracker.calls(bar, () => {});
+  callsbar();
+}, err
+);
+
+assert.throws(() => {
+  const callsbar = tracker.calls(bar, null);
+  callsbar();
+}, err
+);
+
+// Expects an error as tracker.calls() cannot be called within a process exit
+// handler.
+process.on('exit', () => {
+  assert.throws(() => tracker.calls(bar, 1), {
+    code: 'ERR_UNAVAILABLE_DURING_EXIT',
+  });
+});
+
+const msg = 'Expected to throw';
+
+function func() {
+  throw new Error(msg);
+}
+
+const callsfunc = tracker.calls(func, 1);
+
+// Expects callsfunc() to call func() which throws an error.
+assert.throws(
+  () => callsfunc(),
+  { message: msg }
+);
diff --git a/test/parallel/test-assert-calltracker-report.js b/test/parallel/test-assert-calltracker-report.js
new file mode 100644
index 00000000000000..79186c88fd058b
--- /dev/null
+++ b/test/parallel/test-assert-calltracker-report.js
@@ -0,0 +1,32 @@
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// This test ensures that the assert.CallTracker.report() works as intended.
+
+const tracker = new assert.CallTracker();
+
+function foo() {}
+
+const callsfoo = tracker.calls(foo, 1);
+
+// Ensures that foo was added to the callChecks array.
+if (tracker.report()[0].operator !== 'foo') {
+  process.exit(1);
+}
+
+callsfoo();
+
+// Ensures that foo was removed from the callChecks array after being called the
+// expected number of times.
+if (typeof tracker.report()[0] === undefined) {
+  process.exit(1);
+}
+
+callsfoo();
+
+// Ensures that foo was added back to the callChecks array after being called
+// more than the expected number of times.
+if (tracker.report()[0].operator !== 'foo') {
+  process.exit(1);
+}
diff --git a/test/parallel/test-assert-calltracker-verify.js b/test/parallel/test-assert-calltracker-verify.js
new file mode 100644
index 00000000000000..75d20bf9c49c38
--- /dev/null
+++ b/test/parallel/test-assert-calltracker-verify.js
@@ -0,0 +1,32 @@
+'use strict';
+require('../common');
+const assert = require('assert');
+
+// This test ensures that assert.CallTracker.verify() works as intended.
+
+const tracker = new assert.CallTracker();
+
+const msg = 'Function(s) were not called the expected number of times';
+
+function foo() {}
+
+const callsfoo = tracker.calls(foo, 1);
+
+// Expects an error as callsfoo() was called less than one time.
+assert.throws(
+  () => tracker.verify(),
+  { message: msg }
+);
+
+callsfoo();
+
+// Will throw an error if callsfoo() isn't called exactly once.
+tracker.verify();
+
+callsfoo();
+
+// Expects an error as callsfoo() was called more than once.
+assert.throws(
+  () => tracker.verify(),
+  { message: msg }
+);

From 6c3d968e310af3b91e6ff0c31c6487170c86d551 Mon Sep 17 00:00:00 2001
From: Robert Nagy <ronagy@icloud.com>
Date: Sat, 21 Dec 2019 12:08:36 +0100
Subject: [PATCH 03/10] stream: pipeline should use req.abort() to destroy
 response

destroy(err) on http response will propagate the error to the
request causing 'error' to be unexpectedly emitted. Furthermore,
response.destroy() unlike request.abort() does not _dump buffered
data.

Fixes a breaking change introduced in https://github.com/nodejs/node/commit/648088289d619bfb149fe90316ce0127083c4c99.

Prefer res.req.abort() over res.destroy() until this situation is
clarified.

Fixes: https://github.com/nodejs/node/issues/31029
Refs: https://github.com/nodejs/node/commit/648088289d619bfb149fe90316ce0127083c4c99

PR-URL: https://github.com/nodejs/node/pull/31054
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
---
 lib/internal/streams/pipeline.js      | 15 +++--------
 test/parallel/test-stream-pipeline.js | 37 ++++++++++++++++++++++++++-
 2 files changed, 39 insertions(+), 13 deletions(-)

diff --git a/lib/internal/streams/pipeline.js b/lib/internal/streams/pipeline.js
index ed5556e5d0a600..92a91c30171af1 100644
--- a/lib/internal/streams/pipeline.js
+++ b/lib/internal/streams/pipeline.js
@@ -17,7 +17,7 @@ const {
 } = require('internal/errors').codes;
 
 function isRequest(stream) {
-  return stream.setHeader && typeof stream.abort === 'function';
+  return stream && stream.setHeader && typeof stream.abort === 'function';
 }
 
 function destroyer(stream, reading, writing, callback) {
@@ -43,22 +43,13 @@ function destroyer(stream, reading, writing, callback) {
 
     // request.destroy just do .end - .abort is what we want
     if (isRequest(stream)) return stream.abort();
-    if (typeof stream.destroy === 'function') {
-      if (stream.req && stream._writableState === undefined) {
-        // This is a ClientRequest
-        // TODO(mcollina): backward compatible fix to avoid crashing.
-        // Possibly remove in a later semver-major change.
-        stream.req.on('error', noop);
-      }
-      return stream.destroy(err);
-    }
+    if (isRequest(stream.req)) return stream.req.abort();
+    if (typeof stream.destroy === 'function') return stream.destroy(err);
 
     callback(err || new ERR_STREAM_DESTROYED('pipe'));
   };
 }
 
-function noop() {}
-
 function pipe(from, to) {
   return from.pipe(to);
 }
diff --git a/test/parallel/test-stream-pipeline.js b/test/parallel/test-stream-pipeline.js
index 4a41f053bd0a85..27fff7756f5e16 100644
--- a/test/parallel/test-stream-pipeline.js
+++ b/test/parallel/test-stream-pipeline.js
@@ -1,7 +1,14 @@
 'use strict';
 
 const common = require('../common');
-const { Stream, Writable, Readable, Transform, pipeline } = require('stream');
+const {
+  Stream,
+  Writable,
+  Readable,
+  Transform,
+  pipeline,
+  PassThrough
+} = require('stream');
 const assert = require('assert');
 const http = require('http');
 const { promisify } = require('util');
@@ -483,3 +490,31 @@ const { promisify } = require('util');
     { code: 'ERR_INVALID_CALLBACK' }
   );
 }
+
+{
+  const server = http.Server(function(req, res) {
+    res.write('asd');
+  });
+  server.listen(0, function() {
+    http.get({ port: this.address().port }, (res) => {
+      const stream = new PassThrough();
+
+      // NOTE: 2 because Node 12 streams can emit 'error'
+      // multiple times.
+      stream.on('error', common.mustCall(2));
+
+      pipeline(
+        res,
+        stream,
+        common.mustCall((err) => {
+          assert.ok(err);
+          // TODO(ronag):
+          // assert.strictEqual(err.message, 'oh no');
+          server.close();
+        })
+      );
+
+      stream.destroy(new Error('oh no'));
+    }).on('error', common.mustNotCall());
+  });
+}

From 8069f8d4324d1fd05b5e2594ef89dba01263367a Mon Sep 17 00:00:00 2001
From: Pranshu Srivastava <rexagod@gmail.com>
Date: Sun, 3 May 2020 11:02:13 +0530
Subject: [PATCH 04/10] http: don't throw on `Uint8Array`s for
 `http.ServerResponse#write`

Don't throw errors on Uint8Arrays and added test for all
valid types.

Backport-PR-URL: https://github.com/nodejs/node/pull/33488
PR-URL: https://github.com/nodejs/node/pull/33155
Fixes: https://github.com/nodejs/node/issues/33379
Refs: https://github.com/nodejs/node/issues/29829
Reviewed-By: Robert Nagy <ronagy@icloud.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Zeyu Yang <himself65@outlook.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
---
 lib/_http_outgoing.js                         |  8 ++++---
 test/parallel/test-http-outgoing-proto.js     |  4 ++--
 .../test-http-outgoing-write-types.js         | 24 +++++++++++++++++++
 3 files changed, 31 insertions(+), 5 deletions(-)
 create mode 100644 test/parallel/test-http-outgoing-write-types.js

diff --git a/lib/_http_outgoing.js b/lib/_http_outgoing.js
index 606c3da9bd75fc..442369581d3779 100644
--- a/lib/_http_outgoing.js
+++ b/lib/_http_outgoing.js
@@ -60,6 +60,7 @@ const {
   hideStackFrames
 } = require('internal/errors');
 const { validateString } = require('internal/validators');
+const { isUint8Array } = require('internal/util/types');
 
 const HIGH_WATER_MARK = getDefaultHighWaterMark();
 const { CRLF, debug } = common;
@@ -649,9 +650,9 @@ function write_(msg, chunk, encoding, callback, fromEnd) {
     return true;
   }
 
-  if (!fromEnd && typeof chunk !== 'string' && !(chunk instanceof Buffer)) {
+  if (!fromEnd && typeof chunk !== 'string' && !isUint8Array(chunk)) {
     throw new ERR_INVALID_ARG_TYPE('first argument',
-                                   ['string', 'Buffer'], chunk);
+                                   ['string', 'Buffer', 'Uint8Array'], chunk);
   }
 
   if (!fromEnd && msg.connection && !msg.connection.writableCorked) {
@@ -742,7 +743,8 @@ OutgoingMessage.prototype.end = function end(chunk, encoding, callback) {
 
   if (chunk) {
     if (typeof chunk !== 'string' && !(chunk instanceof Buffer)) {
-      throw new ERR_INVALID_ARG_TYPE('chunk', ['string', 'Buffer'], chunk);
+      throw new ERR_INVALID_ARG_TYPE(
+        'chunk', ['string', 'Buffer', 'Uint8Array'], chunk);
     }
     if (!this._header) {
       if (typeof chunk === 'string')
diff --git a/test/parallel/test-http-outgoing-proto.js b/test/parallel/test-http-outgoing-proto.js
index b037c88c6833e9..638e860f62b538 100644
--- a/test/parallel/test-http-outgoing-proto.js
+++ b/test/parallel/test-http-outgoing-proto.js
@@ -80,7 +80,7 @@ assert.throws(() => {
   code: 'ERR_INVALID_ARG_TYPE',
   name: 'TypeError',
   message: 'The first argument must be of type string or an instance of ' +
-           'Buffer. Received undefined'
+           'Buffer or Uint8Array. Received undefined'
 });
 
 assert.throws(() => {
@@ -90,7 +90,7 @@ assert.throws(() => {
   code: 'ERR_INVALID_ARG_TYPE',
   name: 'TypeError',
   message: 'The first argument must be of type string or an instance of ' +
-           'Buffer. Received type number (1)'
+           'Buffer or Uint8Array. Received type number (1)'
 });
 
 // addTrailers()
diff --git a/test/parallel/test-http-outgoing-write-types.js b/test/parallel/test-http-outgoing-write-types.js
new file mode 100644
index 00000000000000..6257b87eea8eb1
--- /dev/null
+++ b/test/parallel/test-http-outgoing-write-types.js
@@ -0,0 +1,24 @@
+'use strict';
+const common = require('../common');
+const assert = require('assert');
+const http = require('http');
+
+const httpServer = http.createServer(common.mustCall(function(req, res) {
+  httpServer.close();
+  assert.throws(() => {
+    res.write(['Throws.']);
+  }, {
+    code: 'ERR_INVALID_ARG_TYPE'
+  });
+  // should not throw
+  res.write('1a2b3c');
+  // should not throw
+  res.write(new Uint8Array(1024));
+  // should not throw
+  res.write(Buffer.from('1'.repeat(1024)));
+  res.end();
+}));
+
+httpServer.listen(0, common.mustCall(function() {
+  http.get({ port: this.address().port });
+}));

From 11a87ed2207b313e996809a7991a9327aaf4d793 Mon Sep 17 00:00:00 2001
From: Alex R <alexei.rudenko@gmail.com>
Date: Wed, 30 Oct 2019 23:33:33 +0100
Subject: [PATCH 05/10] http: fix incorrect headersTimeout measurement

For keep-alive connections, the headersTimeout may fire during
subsequent request because the measurement was reset after
a request and not before a request.

Backport-PR-URL: https://github.com/nodejs/node/pull/34131
PR-URL: https://github.com/nodejs/node/pull/32329
Fixes: https://github.com/nodejs/node/issues/27363
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
---
 lib/_http_client.js                           |  3 +-
 lib/_http_common.js                           |  2 +
 lib/_http_server.js                           | 49 ++++--------------
 src/node_http_parser_impl.h                   | 37 +++++++++++++-
 test/async-hooks/test-graph.http.js           |  4 +-
 ...low-headers-keepalive-multiple-requests.js | 51 +++++++++++++++++++
 6 files changed, 103 insertions(+), 43 deletions(-)
 create mode 100644 test/parallel/test-http-slow-headers-keepalive-multiple-requests.js

diff --git a/lib/_http_client.js b/lib/_http_client.js
index dda29e3e8e6be5..9cf59c60577cc5 100644
--- a/lib/_http_client.js
+++ b/lib/_http_client.js
@@ -674,7 +674,8 @@ function tickOnSocket(req, socket) {
   parser.initialize(HTTPParser.RESPONSE,
                     new HTTPClientAsyncResource('HTTPINCOMINGMESSAGE', req),
                     req.insecureHTTPParser === undefined ?
-                      isLenient() : req.insecureHTTPParser);
+                      isLenient() : req.insecureHTTPParser,
+                    0);
   parser.socket = socket;
   parser.outgoing = req;
   req.parser = parser;
diff --git a/lib/_http_common.js b/lib/_http_common.js
index dda2adea9a949b..3f8ca0e52e9ac8 100644
--- a/lib/_http_common.js
+++ b/lib/_http_common.js
@@ -50,6 +50,7 @@ const kOnHeadersComplete = HTTPParser.kOnHeadersComplete | 0;
 const kOnBody = HTTPParser.kOnBody | 0;
 const kOnMessageComplete = HTTPParser.kOnMessageComplete | 0;
 const kOnExecute = HTTPParser.kOnExecute | 0;
+const kOnTimeout = HTTPParser.kOnTimeout | 0;
 
 const MAX_HEADER_PAIRS = 2000;
 
@@ -168,6 +169,7 @@ const parsers = new FreeList('parsers', 1000, function parsersCb() {
   parser[kOnHeadersComplete] = parserOnHeadersComplete;
   parser[kOnBody] = parserOnBody;
   parser[kOnMessageComplete] = parserOnMessageComplete;
+  parser[kOnTimeout] = null;
 
   return parser;
 });
diff --git a/lib/_http_server.js b/lib/_http_server.js
index 86340e78877a04..a7c867d27f9229 100644
--- a/lib/_http_server.js
+++ b/lib/_http_server.js
@@ -48,7 +48,6 @@ const { OutgoingMessage } = require('_http_outgoing');
 const {
   kOutHeaders,
   kNeedDrain,
-  nowDate,
   emitStatistics
 } = require('internal/http');
 const {
@@ -143,6 +142,7 @@ const STATUS_CODES = {
 };
 
 const kOnExecute = HTTPParser.kOnExecute | 0;
+const kOnTimeout = HTTPParser.kOnTimeout | 0;
 
 class HTTPServerAsyncResource {
   constructor(type, socket) {
@@ -422,11 +422,9 @@ function connectionListenerInternal(server, socket) {
     new HTTPServerAsyncResource('HTTPINCOMINGMESSAGE', socket),
     server.insecureHTTPParser === undefined ?
       isLenient() : server.insecureHTTPParser,
+    server.headersTimeout || 0,
   );
   parser.socket = socket;
-
-  // We are starting to wait for our headers.
-  parser.parsingHeadersStart = nowDate();
   socket.parser = parser;
 
   // Propagate headers limit from server instance to parser
@@ -478,6 +476,9 @@ function connectionListenerInternal(server, socket) {
   parser[kOnExecute] =
     onParserExecute.bind(undefined, server, socket, parser, state);
 
+  parser[kOnTimeout] =
+    onParserTimeout.bind(undefined, server, socket);
+
   socket._paused = false;
 }
 
@@ -566,25 +567,15 @@ function socketOnData(server, socket, parser, state, d) {
 
 function onParserExecute(server, socket, parser, state, ret) {
   socket._unrefTimer();
-  const start = parser.parsingHeadersStart;
   debug('SERVER socketOnParserExecute %d', ret);
+  onParserExecuteCommon(server, socket, parser, state, ret, undefined);
+}
 
-  // If we have not parsed the headers, destroy the socket
-  // after server.headersTimeout to protect from DoS attacks.
-  // start === 0 means that we have parsed headers, while
-  // server.headersTimeout === 0 means user disabled this check.
-  if (
-    start !== 0 && server.headersTimeout &&
-    nowDate() - start > server.headersTimeout
-  ) {
-    const serverTimeout = server.emit('timeout', socket);
-
-    if (!serverTimeout)
-      socket.destroy();
-    return;
-  }
+function onParserTimeout(server, socket) {
+  const serverTimeout = server.emit('timeout', socket);
 
-  onParserExecuteCommon(server, socket, parser, state, ret, undefined);
+  if (!serverTimeout)
+    socket.destroy();
 }
 
 const noop = () => {};
@@ -721,13 +712,6 @@ function emitCloseNT(self) {
 function parserOnIncoming(server, socket, state, req, keepAlive) {
   resetSocketTimeout(server, socket, state);
 
-  if (server.keepAliveTimeout > 0) {
-    req.on('end', resetHeadersTimeoutOnReqEnd);
-  }
-
-  // Set to zero to communicate that we have finished parsing.
-  socket.parser.parsingHeadersStart = 0;
-
   if (req.upgrade) {
     req.upgrade = req.method === 'CONNECT' ||
                   server.listenerCount('upgrade') > 0;
@@ -852,17 +836,6 @@ function generateSocketListenerWrapper(originalFnName) {
   };
 }
 
-function resetHeadersTimeoutOnReqEnd() {
-  debug('resetHeadersTimeoutOnReqEnd');
-
-  const parser = this.socket.parser;
-  // Parser can be null if the socket was destroyed
-  // in that case, there is nothing to do.
-  if (parser) {
-    parser.parsingHeadersStart = nowDate();
-  }
-}
-
 module.exports = {
   STATUS_CODES,
   Server,
diff --git a/src/node_http_parser_impl.h b/src/node_http_parser_impl.h
index e1a99db316a060..22aebad0057b71 100644
--- a/src/node_http_parser_impl.h
+++ b/src/node_http_parser_impl.h
@@ -78,6 +78,7 @@ const uint32_t kOnHeadersComplete = 1;
 const uint32_t kOnBody = 2;
 const uint32_t kOnMessageComplete = 3;
 const uint32_t kOnExecute = 4;
+const uint32_t kOnTimeout = 5;
 // Any more fields than this will be flushed into JS
 const size_t kMaxHeaderFieldsCount = 32;
 
@@ -185,6 +186,7 @@ class Parser : public AsyncWrap, public StreamListener {
     num_fields_ = num_values_ = 0;
     url_.Reset();
     status_message_.Reset();
+    header_parsing_start_time_ = uv_hrtime();
     return 0;
   }
 
@@ -518,9 +520,16 @@ class Parser : public AsyncWrap, public StreamListener {
     Environment* env = Environment::GetCurrent(args);
     bool lenient = args[2]->IsTrue();
 
+    uint64_t headers_timeout = 0;
+
     CHECK(args[0]->IsInt32());
     CHECK(args[1]->IsObject());
 
+    if (args.Length() > 3) {
+      CHECK(args[3]->IsInt32());
+      headers_timeout = args[3].As<Int32>()->Value();
+    }
+
     parser_type_t type =
         static_cast<parser_type_t>(args[0].As<Int32>()->Value());
 
@@ -537,7 +546,7 @@ class Parser : public AsyncWrap, public StreamListener {
 
     parser->set_provider_type(provider);
     parser->AsyncReset(args[1].As<Object>());
-    parser->Init(type, lenient);
+    parser->Init(type, lenient, headers_timeout);
   }
 
   template <bool should_pause>
@@ -645,6 +654,24 @@ class Parser : public AsyncWrap, public StreamListener {
     if (ret.IsEmpty())
       return;
 
+    // check header parsing time
+    if (header_parsing_start_time_ != 0 && headers_timeout_ != 0) {
+      uint64_t now = uv_hrtime();
+      uint64_t parsing_time = (now - header_parsing_start_time_) / 1e6;
+
+      if (parsing_time > headers_timeout_) {
+        Local<Value> cb =
+            object()->Get(env()->context(), kOnTimeout).ToLocalChecked();
+
+        if (!cb->IsFunction())
+          return;
+
+        MakeCallback(cb.As<Function>(), 0, nullptr);
+
+        return;
+      }
+    }
+
     Local<Value> cb =
         object()->Get(env()->context(), kOnExecute).ToLocalChecked();
 
@@ -821,7 +848,7 @@ class Parser : public AsyncWrap, public StreamListener {
   }
 
 
-  void Init(parser_type_t type, bool lenient) {
+  void Init(parser_type_t type, bool lenient, uint64_t headers_timeout) {
 #ifdef NODE_EXPERIMENTAL_HTTP
     llhttp_init(&parser_, type, &settings);
     llhttp_set_lenient(&parser_, lenient);
@@ -836,6 +863,8 @@ class Parser : public AsyncWrap, public StreamListener {
     num_values_ = 0;
     have_flushed_ = false;
     got_exception_ = false;
+    header_parsing_start_time_ = 0;
+    headers_timeout_ = headers_timeout;
   }
 
 
@@ -884,6 +913,8 @@ class Parser : public AsyncWrap, public StreamListener {
   bool pending_pause_ = false;
   uint64_t header_nread_ = 0;
 #endif  /* NODE_EXPERIMENTAL_HTTP */
+  uint64_t headers_timeout_;
+  uint64_t header_parsing_start_time_ = 0;
 
   // These are helper functions for filling `http_parser_settings`, which turn
   // a member function of Parser into a C-style HTTP parser callback.
@@ -957,6 +988,8 @@ void InitializeHttpParser(Local<Object> target,
          Integer::NewFromUnsigned(env->isolate(), kOnMessageComplete));
   t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnExecute"),
          Integer::NewFromUnsigned(env->isolate(), kOnExecute));
+  t->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "kOnTimeout"),
+         Integer::NewFromUnsigned(env->isolate(), kOnTimeout));
 
   Local<Array> methods = Array::New(env->isolate());
 #define V(num, name, string)                                                  \
diff --git a/test/async-hooks/test-graph.http.js b/test/async-hooks/test-graph.http.js
index cd34de19f780d1..924259ffe28c05 100644
--- a/test/async-hooks/test-graph.http.js
+++ b/test/async-hooks/test-graph.http.js
@@ -44,8 +44,8 @@ process.on('exit', () => {
         id: 'httpincomingmessage:1',
         triggerAsyncId: 'tcp:2' },
       { type: 'Timeout',
-        id: 'timeout:2',
-        triggerAsyncId: 'tcp:2' },
+        id: 'timeout:1',
+        triggerAsyncId: 'httpincomingmessage:1' },
       { type: 'SHUTDOWNWRAP',
         id: 'shutdown:1',
         triggerAsyncId: 'tcp:2' } ]
diff --git a/test/parallel/test-http-slow-headers-keepalive-multiple-requests.js b/test/parallel/test-http-slow-headers-keepalive-multiple-requests.js
new file mode 100644
index 00000000000000..9ea76e8e56e952
--- /dev/null
+++ b/test/parallel/test-http-slow-headers-keepalive-multiple-requests.js
@@ -0,0 +1,51 @@
+'use strict';
+
+const common = require('../common');
+const http = require('http');
+const net = require('net');
+const { finished } = require('stream');
+
+const headers =
+  'GET / HTTP/1.1\r\n' +
+  'Host: localhost\r\n' +
+  'Connection: keep-alive\r\n' +
+  'Agent: node\r\n';
+
+const baseTimeout = 1000;
+
+const server = http.createServer(common.mustCall((req, res) => {
+  req.resume();
+  res.writeHead(200);
+  res.end();
+}, 2));
+
+server.keepAliveTimeout = 10 * baseTimeout;
+server.headersTimeout = baseTimeout;
+
+server.once('timeout', common.mustNotCall((socket) => {
+  socket.destroy();
+}));
+
+server.listen(0, () => {
+  const client = net.connect(server.address().port);
+
+  // first request
+  client.write(headers);
+  client.write('\r\n');
+
+  setTimeout(() => {
+    // second request
+    client.write(headers);
+    // `headersTimeout` doesn't seem to fire if request
+    // is sent altogether.
+    setTimeout(() => {
+      client.write('\r\n');
+      client.end();
+    }, 10);
+  }, baseTimeout + 10);
+
+  client.resume();
+  finished(client, common.mustCall((err) => {
+    server.close();
+  }));
+});

From b7fb94d8d9660f304bb2e1405d768a468d0577c4 Mon Sep 17 00:00:00 2001
From: cjihrig <cjihrig@gmail.com>
Date: Thu, 26 Mar 2020 01:07:31 -0400
Subject: [PATCH 06/10] doc: deprecate process.umask() with no arguments

This commit introduces a documentation deprecation for calling
process.umask() with no arguments.

Backport-PR-URL: https://github.com/nodejs/node/pull/34591
PR-URL: https://github.com/nodejs/node/pull/32499
Fixes: https://github.com/nodejs/node/issues/32321
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
---
 doc/api/deprecations.md | 18 ++++++++++++++++++
 doc/api/process.md      | 10 ++++++++++
 2 files changed, 28 insertions(+)

diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md
index 0d3f6a785be2aa..c850c5c16cf781 100644
--- a/doc/api/deprecations.md
+++ b/doc/api/deprecations.md
@@ -2542,6 +2542,24 @@ accordingly instead to avoid the ambigiuty.
 To maintain existing behaviour `response.finished` should be replaced with
 `response.writableEnded`.
 
+<a id="DEP0139"></a>
+### DEP0139: `process.umask()` with no arguments
+<!-- YAML
+changes:
+  - version:
+    - v14.0.0
+    - REPLACEME
+    pr-url: https://github.com/nodejs/node/pull/32499
+    description: Documentation-only deprecation.
+-->
+
+Type: Documentation-only
+
+Calling `process.umask()` with no arguments causes the process-wide umask to be
+written twice. This introduces a race condition between threads, and is a
+potential security vulnerability. There is no safe, cross-platform alternative
+API.
+
 [`--http-parser=legacy`]: cli.html#cli_http_parser_library
 [`--pending-deprecation`]: cli.html#cli_pending_deprecation
 [`--throw-deprecation`]: cli.html#cli_throw_deprecation
diff --git a/doc/api/process.md b/doc/api/process.md
index 2fb0b77f7df702..d9b776fdbc9f04 100644
--- a/doc/api/process.md
+++ b/doc/api/process.md
@@ -2396,8 +2396,18 @@ flag's behavior.
 ## `process.umask([mask])`
 <!-- YAML
 added: v0.1.19
+changes:
+  - version:
+    - v14.0.0
+    - REPLACEME
+    pr-url: https://github.com/nodejs/node/pull/32499
+    description: Calling `process.umask()` with no arguments is deprecated.
+
 -->
 
+> Stability: 0 - Deprecated. Calling `process.umask()` with no arguments is
+> deprecated. No alternative is provided.
+
 * `mask` {string|integer}
 
 The `process.umask()` method sets or returns the Node.js process's file mode

From bb0cc003b70e30b804171739abaeb239d05ad422 Mon Sep 17 00:00:00 2001
From: Rich Trott <rtrott@gmail.com>
Date: Tue, 7 Apr 2020 16:17:14 -0700
Subject: [PATCH 07/10] doc: split process.umask() entry into two

Split doc entries for process.umask() into one entry for process.umask()
(which is deprecated) and another for `process.umask(mask)` which is
not deprecated.

Backport-PR-URL: https://github.com/nodejs/node/pull/34591
PR-URL: https://github.com/nodejs/node/pull/32711
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
---
 doc/api/deprecations.md |  4 ++--
 doc/api/process.md      | 27 +++++++++++++++++----------
 2 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md
index c850c5c16cf781..c2bac5198243f4 100644
--- a/doc/api/deprecations.md
+++ b/doc/api/deprecations.md
@@ -2547,15 +2547,15 @@ To maintain existing behaviour `response.finished` should be replaced with
 <!-- YAML
 changes:
   - version:
-    - v14.0.0
     - REPLACEME
+    - v14.0.0
     pr-url: https://github.com/nodejs/node/pull/32499
     description: Documentation-only deprecation.
 -->
 
 Type: Documentation-only
 
-Calling `process.umask()` with no arguments causes the process-wide umask to be
+Calling `process.umask()` with no argument causes the process-wide umask to be
 written twice. This introduces a race condition between threads, and is a
 potential security vulnerability. There is no safe, cross-platform alternative
 API.
diff --git a/doc/api/process.md b/doc/api/process.md
index d9b776fdbc9f04..33a3debc0b53ea 100644
--- a/doc/api/process.md
+++ b/doc/api/process.md
@@ -2393,27 +2393,35 @@ documentation for the [`'warning'` event][process_warning] and the
 [`emitWarning()` method][process_emit_warning] for more information about this
 flag's behavior.
 
-## `process.umask([mask])`
+## `process.umask()`
 <!-- YAML
 added: v0.1.19
 changes:
   - version:
-    - v14.0.0
     - REPLACEME
+    - v14.0.0
     pr-url: https://github.com/nodejs/node/pull/32499
     description: Calling `process.umask()` with no arguments is deprecated.
 
 -->
 
-> Stability: 0 - Deprecated. Calling `process.umask()` with no arguments is
-> deprecated. No alternative is provided.
+> Stability: 0 - Deprecated. Calling `process.umask()` with no argument causes
+> the process-wide umask to be written twice. This introduces a race condition
+> between threads, and is a potential security vulnerability. There is no safe,
+> cross-platform alternative API.
+
+`process.umask()` returns the Node.js process's file mode creation mask. Child
+processes inherit the mask from the parent process.
+
+## `process.umask(mask)`
+<!-- YAML
+added: v0.1.19
+-->
 
 * `mask` {string|integer}
 
-The `process.umask()` method sets or returns the Node.js process's file mode
-creation mask. Child processes inherit the mask from the parent process. Invoked
-without an argument, the current mask is returned, otherwise the umask is set to
-the argument value and the previous mask is returned.
+`process.umask(mask)` sets the Node.js process's file mode creation mask. Child
+processes inherit the mask from the parent process. Returns the previous mask.
 
 ```js
 const newmask = 0o022;
@@ -2423,8 +2431,7 @@ console.log(
 );
 ```
 
-[`Worker`][] threads are able to read the umask, however attempting to set the
-umask will result in a thrown exception.
+In [`Worker`][] threads, `process.umask(mask)` will throw an exception.
 
 ## `process.uptime()`
 <!-- YAML

From e5049f299167b5fc4c684e496e63f0ce9f28e14d Mon Sep 17 00:00:00 2001
From: Zhao Jiazhong <zhaojiazhong-hf@loongson.cn>
Date: Sat, 4 Jul 2020 03:16:53 -0400
Subject: [PATCH 08/10] deps: V8: cherry-pick 7889803e82d3

Original commit message:

    [mips] Use t9 as the function call register.

    on mips, we should use t9 when jump to a ExternalReference, because
    the callee function will consider t9 as the function start address.

    Change-Id: I56e2bf073fd24b2f3434dfd255d48264bfd0b2cd
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1826417
    Auto-Submit: Yu Yin <xwafish@gmail.com>
    Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
    Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
    Cr-Commit-Position: refs/heads/master@{#63988}

Refs: https://github.com/v8/v8/commit/7889803e82d33c7837d9ff22e185e0800f5d5cf0

PR-URL: https://github.com/nodejs/node/pull/34214
Fixes: https://github.com/nodejs/node/issues/33703
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
Reviewed-By: Beth Griggs <Bethany.Griggs@uk.ibm.com>
---
 common.gypi                                          | 2 +-
 deps/v8/src/codegen/mips/macro-assembler-mips.cc     | 6 ++----
 deps/v8/src/codegen/mips64/macro-assembler-mips64.cc | 6 ++----
 3 files changed, 5 insertions(+), 9 deletions(-)

diff --git a/common.gypi b/common.gypi
index cebf2121ff9130..0dc9b046298aff 100644
--- a/common.gypi
+++ b/common.gypi
@@ -34,7 +34,7 @@
 
     # Reset this number to 0 on major V8 upgrades.
     # Increment by one for each non-official patch applied to deps/v8.
-    'v8_embedder_string': '-node.39',
+    'v8_embedder_string': '-node.40',
 
     ##### V8 defaults for Node.js #####
 
diff --git a/deps/v8/src/codegen/mips/macro-assembler-mips.cc b/deps/v8/src/codegen/mips/macro-assembler-mips.cc
index 2e4698a9e71c78..76503f6d6a544a 100644
--- a/deps/v8/src/codegen/mips/macro-assembler-mips.cc
+++ b/deps/v8/src/codegen/mips/macro-assembler-mips.cc
@@ -3853,10 +3853,8 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
 }
 
 void TurboAssembler::Jump(const ExternalReference& reference) {
-  UseScratchRegisterScope temps(this);
-  Register scratch = temps.Acquire();
-  li(scratch, reference);
-  Jump(scratch);
+  li(t9, reference);
+  Jump(t9);
 }
 
 void MacroAssembler::JumpIfIsInRange(Register value, unsigned lower_limit,
diff --git a/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc b/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc
index b3537860643784..e1eabc18362a9f 100644
--- a/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc
+++ b/deps/v8/src/codegen/mips64/macro-assembler-mips64.cc
@@ -4202,10 +4202,8 @@ void TurboAssembler::Jump(Handle<Code> code, RelocInfo::Mode rmode,
 }
 
 void TurboAssembler::Jump(const ExternalReference& reference) {
-  UseScratchRegisterScope temps(this);
-  Register scratch = temps.Acquire();
-  li(scratch, reference);
-  Jump(scratch);
+  li(t9, reference);
+  Jump(t9);
 }
 
 // Note: To call gcc-compiled C code on mips, you must call through t9.

From 729799d81ac239ab08fb537842bdb9af49cd066f Mon Sep 17 00:00:00 2001
From: Antoine du HAMEL <duhamelantoine1995@gmail.com>
Date: Wed, 11 Mar 2020 23:44:31 +0100
Subject: [PATCH 09/10] module: deprecate module.parent
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This feature does not work when a module is imported using ECMAScript
modules specification, therefore it is deprecated.

Fixes: https://github.com/nodejs/modules/issues/469

PR-URL: https://github.com/nodejs/node/pull/32217
Backport-PR-URL: https://github.com/nodejs/node/pull/34592
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Bradley Farias <bradley.meck@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de>
---
 doc/api/deprecations.md | 35 +++++++++++++++++++++++++++++++++++
 doc/api/modules.md      | 14 ++++++++++++--
 2 files changed, 47 insertions(+), 2 deletions(-)

diff --git a/doc/api/deprecations.md b/doc/api/deprecations.md
index c2bac5198243f4..a12ca3dd7b5626 100644
--- a/doc/api/deprecations.md
+++ b/doc/api/deprecations.md
@@ -2560,6 +2560,41 @@ written twice. This introduces a race condition between threads, and is a
 potential security vulnerability. There is no safe, cross-platform alternative
 API.
 
+<a id="DEP0144"></a>
+### DEP0144: `module.parent`
+<!-- YAML
+changes:
+  - version:
+    - REPLACEME
+    - v14.6.0
+    pr-url: https://github.com/nodejs/node/pull/32217
+    description: Documentation-only deprecation.
+-->
+
+Type: Documentation-only
+
+A CommonJS module can access the first module that required it using
+`module.parent`. This feature is deprecated because it does not work
+consistently in the presence of ECMAScript modules and because it gives an
+inaccurate representation of the CommonJS module graph.
+
+Some modules use it to check if they are the entry point of the current process.
+Instead, it is recommended to compare `require.main` and `module`:
+
+```js
+if (require.main === module) {
+  // Code section that will run only if current file is the entry point.
+}
+```
+
+When looking for the CommonJS modules that have required the current one,
+`require.cache` and `module.children` can be used:
+
+```js
+const moduleParents = Object.values(require.cache)
+  .filter((m) => m.children.includes(module));
+```
+
 [`--http-parser=legacy`]: cli.html#cli_http_parser_library
 [`--pending-deprecation`]: cli.html#cli_pending_deprecation
 [`--throw-deprecation`]: cli.html#cli_throw_deprecation
diff --git a/doc/api/modules.md b/doc/api/modules.md
index 7cb5de8c4589e2..e8215a2ace67ed 100644
--- a/doc/api/modules.md
+++ b/doc/api/modules.md
@@ -894,11 +894,19 @@ loading.
 ### `module.parent`
 <!-- YAML
 added: v0.1.16
+deprecated:
+  - REPLACEME
+  - v14.6.0
 -->
 
-* {module}
+> Stability: 0 - Deprecated: Please use [`require.main`][] and
+> [`module.children`][] instead.
+
+* {module | null | undefined}
 
-The module that first required this one.
+The module that first required this one, or `null` if the current module is the
+entry point of the current process, or `undefined` if the module was loaded by
+something that is not a CommonJS module (E.G.: REPL or `import`).
 
 ### `module.path`
 <!-- YAML
@@ -1122,6 +1130,7 @@ consists of the following keys:
 [`createRequire()`]: #modules_module_createrequire_filename
 [`module` object]: #modules_the_module_object
 [`module.id`]: #modules_module_id
+[`module.children`]: #modules_module_children
 [`path.dirname()`]: path.html#path_path_dirname_path
 [ECMAScript Modules]: esm.html
 [an error]: errors.html#errors_err_require_esm
@@ -1129,6 +1138,7 @@ consists of the following keys:
 [module resolution]: #modules_all_together
 [module wrapper]: #modules_the_module_wrapper
 [native addons]: addons.html
+[`require.main`]: #modules_require_main
 [source map include directives]: https://sourcemaps.info/spec.html#h.lmz475t4mvbx
 [`--enable-source-maps`]: cli.html#cli_enable_source_maps
 [`NODE_V8_COVERAGE=dir`]: cli.html#cli_node_v8_coverage_dir

From c10bfdc0986540849b40d29b90fdfe3c8a199136 Mon Sep 17 00:00:00 2001
From: Milad Farazmand <miladfar@ca.ibm.com>
Date: Thu, 3 Sep 2020 18:48:01 +0000
Subject: [PATCH 10/10] deps: V8: backport 3f071e3e7e15

Original commit message:

    PPC: Optimize clearing higher bits of mulhw/mulhwu

    Change-Id: Ie3e14a6ef4531349e81a8ae741bc7470c7e547ca
    Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2349468
    Reviewed-by: Junliang Yan <jyan@ca.ibm.com>
    Commit-Queue: Milad Farazmand <miladfar@ca.ibm.com>
    Cr-Commit-Position: refs/heads/master@{#69343}

Refs: https://github.com/v8/v8/commit/3f071e3e7e15af187267af6c3b369029e27c8cf5
---
 common.gypi                                            |  2 +-
 deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc | 10 ++++++----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/common.gypi b/common.gypi
index 0dc9b046298aff..0c7fe48b3ee066 100644
--- a/common.gypi
+++ b/common.gypi
@@ -34,7 +34,7 @@
 
     # Reset this number to 0 on major V8 upgrades.
     # Increment by one for each non-official patch applied to deps/v8.
-    'v8_embedder_string': '-node.40',
+    'v8_embedder_string': '-node.41',
 
     ##### V8 defaults for Node.js #####
 
diff --git a/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc b/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc
index 7147448e210bfb..d91d9f1e9a95a8 100644
--- a/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc
+++ b/deps/v8/src/compiler/backend/ppc/code-generator-ppc.cc
@@ -1480,12 +1480,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
       }
       break;
     case kPPC_MulHigh32:
-      __ mulhw(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
-               i.OutputRCBit());
+      __ mulhw(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
+      // High 32 bits are undefined and need to be cleared.
+      __ clrldi(i.OutputRegister(), r0, Operand(32));
       break;
     case kPPC_MulHighU32:
-      __ mulhwu(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
-                i.OutputRCBit());
+      __ mulhwu(r0, i.InputRegister(0), i.InputRegister(1), i.OutputRCBit());
+      // High 32 bits are undefined and need to be cleared.
+      __ clrldi(i.OutputRegister(), r0, Operand(32));
       break;
     case kPPC_MulDouble:
       ASSEMBLE_FLOAT_BINOP_RC(fmul, MiscField::decode(instr->opcode()));