[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#991707: marked as done (unblock: nodejs/12.22.4~dfsg-1)



Your message dated Fri, 30 Jul 2021 16:32:35 +0200
with message-id <CAJxTCxy_20WuHmxObnDmM=7WaB3i9K_CH07WKp6moYPDpiT+9w@mail.gmail.com>
and subject line Re: Bug#991707: Acknowledgement (unblock: nodejs/12.22.4~dfsg-1)
has caused the Debian Bug report #991707,
regarding unblock: nodejs/12.22.4~dfsg-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
991707: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=991707
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
X-Debbugs-Cc: security@debian.org

Please unblock package nodejs

[ Reason ]
Debian security team plans to upload nodejs security updates "as-is",
at least while upstream still maintain nodejs 12.x. This is what was
done in Buster.

Latest security update is 12.22.4 (severity high).
I did not try to get nodejs > 12.21.0 into bullseye up until now
because upstream changes were essentially not concerning the debian package.

However the 12.22.4 release has many v8 fixes, and a security fix (high).


[ Impact ]
If not in Bullseye, it will require users to download nodejs a second time
just after installation, through security updates.
So it will postpone any issue post-release.


[ Tests ]
Usual thorough upstream test suite + all dependents packages tests.

[ Risks ]
Low, but when considering the regressions i saw false positives:
- node-chokidar seems to have a flaky test
- node-esquery, node-caniuse-api, node-browserslist suites fail on their own,
  for an unrelated problem
- node-websocket-driver was already broken, probably for a long time.
  I opened #991700 and will ask its removal from testing.

Also an undocumented internal api has been deprecated, and old modules trying
accessing it will now print a warning (process.binding('http_parser')).
Only node-websocket-driver is actually using it...
A code search shows node-http-signature, node-fastcgi are using it in their
test suites, but it doesn't pose any problem.
https://codesearch.debian.net/search?q=process%5C.binding%5C%28%5B%27%22%5Dhttp_parser%5B%27%22%5D%5C%29&literal=0

[ Checklist ]
  [x] all changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in testing

[ Other info ]
debdiff is without deps/cares (not used), deps/openssl (not used), test/*, benchmark/*, tools/msvs/*.
Still waiting for armhf test results when writing this request.

unblock nodejs/12.22.4~dfsg-1
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/common.gypi nodejs-12.22.4~dfsg/common.gypi
--- nodejs-12.21.0~dfsg/common.gypi	2021-02-23 03:58:04.000000000 +0100
+++ nodejs-12.22.4~dfsg/common.gypi	2021-07-29 12:35:21.000000000 +0200
@@ -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.45',
+    'v8_embedder_string': '-node.56',
 
     ##### V8 defaults for Node.js #####
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/debian/changelog nodejs-12.22.4~dfsg/debian/changelog
--- nodejs-12.21.0~dfsg/debian/changelog	2021-07-03 20:50:29.000000000 +0200
+++ nodejs-12.22.4~dfsg/debian/changelog	2021-07-30 01:02:46.000000000 +0200
@@ -1,3 +1,12 @@
+nodejs (12.22.4~dfsg-1) unstable; urgency=medium
+
+  * New upstream version 12.22.4~dfsg
+    Fixed vulnerabilities:
+    + CVE-2021-22930: Use after free on close http2
+      on stream canceling (High)
+
+ -- Jérémy Lal <kapouer@melix.org>  Fri, 30 Jul 2021 01:02:46 +0200
+
 nodejs (12.21.0~dfsg-5) unstable; urgency=medium
 
   * Patch uvwasi.gyp to honour --shared-libuv. Closes: #990569.
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/cjs-module-lexer/lexer.js nodejs-12.22.4~dfsg/deps/cjs-module-lexer/lexer.js
--- nodejs-12.21.0~dfsg/deps/cjs-module-lexer/lexer.js	2021-02-23 03:58:04.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/cjs-module-lexer/lexer.js	2021-07-29 12:35:21.000000000 +0200
@@ -37,8 +37,6 @@
 const ExportAssign = 1;
 const ExportStar = 2;
 
-const strictReserved = new Set(['implements', 'interface', 'let', 'package', 'private', 'protected', 'public', 'static', 'yield', 'enum']);
-
 function parseCJS (source, name = '@') {
   resetState();
   try {
@@ -49,14 +47,39 @@
     e.loc = pos;
     throw e;
   }
-  const result = { exports: [..._exports].filter(expt => !unsafeGetters.has(expt)), reexports: [...reexports] };
+  const result = { exports: [..._exports].filter(expt => expt !== undefined && !unsafeGetters.has(expt)), reexports: [...reexports].filter(reexpt => reexpt !== undefined) };
   resetState();
   return result;
 }
 
-function addExport (name) {
-  if (!strictReserved.has(name))
-    _exports.add(name);
+function decode (str) {
+  if (str[0] === '"' || str[0] === '\'') {
+    try {
+      const decoded = (0, eval)(str);
+      // Filter to exclude non-matching UTF-16 surrogate strings
+      for (let i = 0; i < decoded.length; i++) {
+        const surrogatePrefix = decoded.charCodeAt(i) & 0xFC00;
+        if (surrogatePrefix < 0xD800) {
+          // Not a surrogate
+          continue;
+        }
+        else if (surrogatePrefix === 0xD800) {
+          // Validate surrogate pair
+          if ((decoded.charCodeAt(++i) & 0xFC00) !== 0xDC00)
+            return;
+        }
+        else {
+          // Out-of-range surrogate code (above 0xD800)
+          return;
+        }
+      }
+      return decoded;
+    }
+    catch {}
+  }
+  else {
+    return str;
+  }
 }
 
 function parseSource (cjsSource) {
@@ -97,7 +120,18 @@
           lastTokenPos = pos;
           continue;
         case 95/*_*/:
-          if (source.startsWith('_export', pos + 1) && (keywordStart(pos) || source.charCodeAt(pos - 1) === 46/*.*/)) {
+          if (source.startsWith('interopRequireWildcard', pos + 1) && (keywordStart(pos) || source.charCodeAt(pos - 1) === 46/*.*/)) {
+            const startPos = pos;
+            pos += 23;
+            if (source.charCodeAt(pos) === 40/*(*/) {
+              pos++;
+              openTokenPosStack[openTokenDepth++] = lastTokenPos;
+              if (tryParseRequire(Import) && keywordStart(startPos)) {
+                tryBacktrackAddStarExportBinding(startPos - 1);
+              }
+            }
+          }
+          else if (source.startsWith('_export', pos + 1) && (keywordStart(pos) || source.charCodeAt(pos - 1) === 46/*.*/)) {
             pos += 8;
             if (source.startsWith('Star', pos))
               pos += 4;
@@ -162,10 +196,8 @@
         // TODO: <!-- XML comment support
         break;
       case 39/*'*/:
-        singleQuoteString();
-        break;
       case 34/*"*/:
-        doubleQuoteString();
+        stringLiteral(ch);
         break;
       case 47/*/*/: {
         const next_ch = source.charCodeAt(pos + 1);
@@ -254,6 +286,48 @@
   }
 }
 
+// `Object.` `prototype.`? hasOwnProperty.call(`  IDENTIFIER `, ` IDENTIFIER$2 `)`
+function tryParseObjectHasOwnProperty (it_id) {
+  ch = commentWhitespace();
+  if (ch !== 79/*O*/ || !source.startsWith('bject', pos + 1)) return false;
+  pos += 6;
+  ch = commentWhitespace();
+  if (ch !== 46/*.*/) return false;
+  pos++;
+  ch = commentWhitespace();
+  if (ch === 112/*p*/) {
+    if (!source.startsWith('rototype', pos + 1)) return false;
+    pos += 9;
+    ch = commentWhitespace();
+    if (ch !== 46/*.*/) return false;
+    pos++;
+    ch = commentWhitespace();
+  }
+  if (ch !== 104/*h*/ || !source.startsWith('asOwnProperty', pos + 1)) return false;
+  pos += 14;
+  ch = commentWhitespace();
+  if (ch !== 46/*.*/) return false;
+  pos++;
+  ch = commentWhitespace();
+  if (ch !== 99/*c*/ || !source.startsWith('all', pos + 1)) return false;
+  pos += 4;
+  ch = commentWhitespace();
+  if (ch !== 40/*(*/) return false;
+  pos++;
+  ch = commentWhitespace();
+  if (!identifier()) return false;
+  ch = commentWhitespace();
+  if (ch !== 44/*,*/) return false;
+  pos++;
+  ch = commentWhitespace();
+  if (!source.startsWith(it_id, pos)) return false;
+  pos += it_id.length;
+  ch = commentWhitespace();
+  if (ch !== 41/*)*/) return false;
+  pos++;
+  return true;
+}
+
 function tryParseObjectDefineOrKeys (keys) {
   pos += 6;
   let revertPos = pos - 1;
@@ -276,11 +350,9 @@
         pos++;
         ch = commentWhitespace();
         if (ch !== 39/*'*/ && ch !== 34/*"*/) break;
-        let quot = ch;
-        const exportPos = ++pos;
-        if (!identifier() || source.charCodeAt(pos) !== quot) break;
-        expt = source.slice(exportPos, pos);
-        pos++;
+        const exportPos = pos;
+        stringLiteral(ch);
+        expt = source.slice(exportPos, ++pos);
         ch = commentWhitespace();
         if (ch !== 44/*,*/) break;
         pos++;
@@ -307,7 +379,7 @@
           pos += 5;
           ch = commentWhitespace();
           if (ch !== 58/*:*/) break;
-          addExport(expt);
+          _exports.add(decode(expt));
           pos = revertPos;
           return;
         }
@@ -350,8 +422,7 @@
           else if (ch === 91/*[*/) {
             pos++;
             ch = commentWhitespace();
-            if (ch === 39/*'*/) singleQuoteString();
-            else if (ch === 34/*"*/) doubleQuoteString();
+            if (ch === 39/*'*/ || ch === 34/*"*/) stringLiteral(ch);
             else break;
             pos++;
             ch = commentWhitespace();
@@ -366,17 +437,21 @@
           if (ch !== 125/*}*/) break;
           pos++;
           ch = commentWhitespace();
+          if (ch === 44/*,*/) {
+            pos++;
+            ch = commentWhitespace();
+          }
           if (ch !== 125/*}*/) break;
           pos++;
           ch = commentWhitespace();
           if (ch !== 41/*)*/) break;
-          addExport(expt);
+          _exports.add(decode(expt));
           return;
         }
         break;
       }
       if (expt) {
-        unsafeGetters.add(expt);
+        unsafeGetters.add(decode(expt));
       }
     }
     else if (keys && ch === 107/*k*/ && source.startsWith('eys', pos + 1)) {
@@ -469,8 +544,94 @@
           if (ch === 59/*;*/)
             pos++;
           ch = commentWhitespace();
+
+          // `if (`
+          if (ch === 105/*i*/ && source.charCodeAt(pos + 1) === 102/*f*/) {
+            let inIf = true;
+            pos += 2;
+            ch = commentWhitespace();
+            if (ch !== 40/*(*/) break;
+            pos++;
+            const ifInnerPos = pos;
+            // `Object.prototype.hasOwnProperty.call(`  IDENTIFIER `, ` IDENTIFIER$2 `)) return` `;`?
+            if (tryParseObjectHasOwnProperty(it_id)) {
+              ch = commentWhitespace();
+              if (ch !== 41/*)*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 114/*r*/ || !source.startsWith('eturn', pos + 1)) break;
+              pos += 6;
+              ch = commentWhitespace();
+              if (ch === 59/*;*/)
+                pos++;
+              ch = commentWhitespace();
+              // match next if
+              if (ch === 105/*i*/ && source.charCodeAt(pos + 1) === 102/*f*/) {
+                pos += 2;
+                ch = commentWhitespace();
+                if (ch !== 40/*(*/) break;
+                pos++;
+              }
+              else {
+                inIf = false;
+              }
+            }
+            else {
+              pos = ifInnerPos;
+            }
+
+            // IDENTIFIER$2 `in` EXPORTS_IDENTIFIER `&&` EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] ===` IDENTIFIER$1 `[` IDENTIFIER$2 `]) return` `;`?
+            if (inIf) {
+              if (!source.startsWith(it_id, pos)) break;
+              pos += it_id.length;
+              ch = commentWhitespace();
+              if (ch !== 105/*i*/ || !source.startsWith('n ', pos + 1)) break;
+              pos += 3;
+              ch = commentWhitespace();
+              if (!readExportsOrModuleDotExports(ch)) break;
+              ch = commentWhitespace();
+              if (ch !== 38/*&*/ || source.charCodeAt(pos + 1) !== 38/*&*/) break;
+              pos += 2;
+              ch = commentWhitespace();
+              if (!readExportsOrModuleDotExports(ch)) break;
+              ch = commentWhitespace();
+              if (ch !== 91/*[*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (!source.startsWith(it_id, pos)) break;
+              pos += it_id.length;
+              ch = commentWhitespace();
+              if (ch !== 93/*]*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 61/*=*/ || !source.startsWith('==', pos + 1)) break;
+              pos += 3;
+              ch = commentWhitespace();
+              if (!source.startsWith(id, pos)) break;
+              pos += id.length;
+              ch = commentWhitespace();
+              if (ch !== 91/*[*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (!source.startsWith(it_id, pos)) break;
+              pos += it_id.length;
+              ch = commentWhitespace();
+              if (ch !== 93/*]*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 41/*)*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 114/*r*/ || !source.startsWith('eturn', pos + 1)) break;
+              pos += 6;
+              ch = commentWhitespace();
+              if (ch === 59/*;*/)
+                pos++;
+              ch = commentWhitespace();
+            }
+          }
         }
-        // `if (` IDENTIFIER$2 `!==` ( `'default'` | `"default"` ) `)`
+        // `if (` IDENTIFIER$2 `!==` ( `'default'` | `"default"` ) (`&& !` IDENTIFIER `.hasOwnProperty(` IDENTIFIER$2 `)`  )? `)`
         else if (ch === 33/*!*/) {
           if (!source.startsWith('==', pos + 1)) break;
           pos += 3;
@@ -483,67 +644,40 @@
           if (ch !== quot) break;
           pos += 1;
           ch = commentWhitespace();
+          if (ch === 38/*&*/) {
+            if (source.charCodeAt(pos + 1) !== 38/*&*/) break;
+            pos += 2;
+            ch = commentWhitespace();
+            if (ch !== 33/*!*/) break;
+            pos += 1;
+            ch = commentWhitespace();
+            if (source.startsWith(id, pos)) {
+              pos += id.length;
+              ch = commentWhitespace();
+              if (ch !== 46/*.*/) break;
+              pos++;
+              ch = commentWhitespace();
+              if (ch !== 104/*h*/ || !source.startsWith('asOwnProperty', pos + 1)) break;
+              pos += 14;
+              ch = commentWhitespace();
+              if (ch !== 40/*(*/) break;
+              pos += 1;
+              ch = commentWhitespace();
+              if (!source.startsWith(it_id, pos)) break;
+              pos += it_id.length;
+              ch = commentWhitespace();
+              if (ch !== 41/*)*/) break;
+              pos += 1;
+            }
+            else if (!tryParseObjectHasOwnProperty(it_id)) break;
+            ch = commentWhitespace();
+          }
           if (ch !== 41/*)*/) break;
           pos += 1;
           ch = commentWhitespace();
         }
         else break;
 
-        // `if (` IDENTIFIER$2 `in` EXPORTS_IDENTIFIER `&&` EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] ===` IDENTIFIER$1 `[` IDENTIFIER$2 `]) return` `;`?
-        if (ch === 105/*i*/ && source.charCodeAt(pos + 1) === 102/*f*/) {
-          pos += 2;
-          ch = commentWhitespace();
-          if (ch !== 40/*(*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (!source.startsWith(it_id, pos)) break;
-          pos += it_id.length;
-          ch = commentWhitespace();
-          if (ch !== 105/*i*/ || !source.startsWith('n ', pos + 1)) break;
-          pos += 3;
-          ch = commentWhitespace();
-          if (!readExportsOrModuleDotExports(ch)) break;
-          ch = commentWhitespace();
-          if (ch !== 38/*&*/ || source.charCodeAt(pos + 1) !== 38/*&*/) break;
-          pos += 2;
-          ch = commentWhitespace();
-          if (!readExportsOrModuleDotExports(ch)) break;
-          ch = commentWhitespace();
-          if (ch !== 91/*[*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (!source.startsWith(it_id, pos)) break;
-          pos += it_id.length;
-          ch = commentWhitespace();
-          if (ch !== 93/*]*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 61/*=*/ || !source.startsWith('==', pos + 1)) break;
-          pos += 3;
-          ch = commentWhitespace();
-          if (!source.startsWith(id, pos)) break;
-          pos += id.length;
-          ch = commentWhitespace();
-          if (ch !== 91/*[*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (!source.startsWith(it_id, pos)) break;
-          pos += it_id.length;
-          ch = commentWhitespace();
-          if (ch !== 93/*]*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 41/*)*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 114/*r*/ || !source.startsWith('eturn', pos + 1)) break;
-          pos += 6;
-          ch = commentWhitespace();
-          if (ch === 59/*;*/)
-            pos++;
-          ch = commentWhitespace();
-        }
-
         // EXPORTS_IDENTIFIER `[` IDENTIFIER$2 `] =` IDENTIFIER$1 `[` IDENTIFIER$2 `]`
         if (readExportsOrModuleDotExports(ch)) {
           ch = commentWhitespace();
@@ -619,12 +753,17 @@
           if (ch !== 103/*g*/ || !source.startsWith('et', pos + 1)) break;
           pos += 3;
           ch = commentWhitespace();
-          if (ch !== 58/*:*/) break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 102/*f*/ || !source.startsWith('unction', pos + 1)) break;
-          pos += 8;
-          ch = commentWhitespace();
+          if (ch === 58/*:*/) {
+            pos++;
+            ch = commentWhitespace();
+            if (ch !== 102/*f*/) break;
+            if (!source.startsWith('unction', pos + 1)) break;
+            pos += 8;
+            let lastPos = pos;
+            ch = commentWhitespace();
+            if (ch !== 40 && (lastPos === pos || !identifier())) break;
+            ch = commentWhitespace();
+          }
           if (ch !== 40/*(*/) break;
           pos++;
           ch = commentWhitespace();
@@ -656,6 +795,10 @@
           if (ch !== 125/*}*/) break;
           pos++;
           ch = commentWhitespace();
+          if (ch === 44/*,*/) {
+            pos++;
+            ch = commentWhitespace();
+          }
           if (ch !== 125/*}*/) break;
           pos++;
           ch = commentWhitespace();
@@ -676,7 +819,7 @@
 
         const starExportSpecifier = starExportMap[id];
         if (starExportSpecifier) {
-          reexports.add(starExportSpecifier);
+          reexports.add(decode(starExportSpecifier));
           pos = revertPos;
           return;
         }
@@ -738,7 +881,7 @@
         const endPos = pos;
         ch = commentWhitespace();
         if (ch === 61/*=*/) {
-          addExport(source.slice(startPos, endPos));
+          _exports.add(decode(source.slice(startPos, endPos)));
           return;
         }
       }
@@ -749,19 +892,15 @@
       pos++;
       ch = commentWhitespace();
       if (ch === 39/*'*/ || ch === 34/*"*/) {
-        pos++;
         const startPos = pos;
-        if (identifier() && source.charCodeAt(pos) === ch) {
-          const endPos = pos++;
-          ch = commentWhitespace();
-          if (ch !== 93/*]*/)
-            break;
-          pos++;
-          ch = commentWhitespace();
-          if (ch !== 61/*=*/)
-            break;
-          addExport(source.slice(startPos, endPos));
-        }
+        stringLiteral(ch);
+        const endPos = ++pos;
+        ch = commentWhitespace();
+        if (ch !== 93/*]*/) break;
+        pos++;
+        ch = commentWhitespace();
+        if (ch !== 61/*=*/) break;
+        _exports.add(decode(source.slice(startPos, endPos)));
       }
       break;
     }
@@ -796,39 +935,21 @@
     if (ch === 40/*(*/) {
       pos++;
       ch = commentWhitespace();
-      const reexportStart = pos + 1;
-      if (ch === 39/*'*/) {
-        singleQuoteString();
-        const reexportEnd = pos++;
-        ch = commentWhitespace();
-        if (ch === 41/*)*/) {
-          switch (requireType) {
-            case ExportAssign:
-              reexports.add(source.slice(reexportStart, reexportEnd));
-              return true;
-            case ExportStar:
-              reexports.add(source.slice(reexportStart, reexportEnd));
-              return true;
-            default:
-              lastStarExportSpecifier = source.slice(reexportStart, reexportEnd);
-              return true;
-          }
-        }
-      }
-      else if (ch === 34/*"*/) {
-        doubleQuoteString();
-        const reexportEnd = pos++;
+      const reexportStart = pos;
+      if (ch === 39/*'*/ || ch === 34/*"*/) {
+        stringLiteral(ch);
+        const reexportEnd = ++pos;
         ch = commentWhitespace();
         if (ch === 41/*)*/) {
           switch (requireType) {
             case ExportAssign:
-              reexports.add(source.slice(reexportStart, reexportEnd));
+              reexports.add(decode(source.slice(reexportStart, reexportEnd)));
               return true;
             case ExportStar:
-              reexports.add(source.slice(reexportStart, reexportEnd));
+              reexports.add(decode(source.slice(reexportStart, reexportEnd)));
               return true;
             default:
-              lastStarExportSpecifier = source.slice(reexportStart, reexportEnd);
+              lastStarExportSpecifier = decode(source.slice(reexportStart, reexportEnd));
               return true;
           }
         }
@@ -857,7 +978,7 @@
         }
         ch = source.charCodeAt(pos);
       }
-      addExport(source.slice(startPos, endPos));
+      _exports.add(decode(source.slice(startPos, endPos)));
     }
     else if (ch === 46/*.*/ && source.startsWith('..', pos + 1)) {
       pos += 3;
@@ -871,21 +992,20 @@
       ch = commentWhitespace();
     }
     else if (ch === 39/*'*/ || ch === 34/*"*/) {
-      const startPos = ++pos;
-      if (identifier() && source.charCodeAt(pos) === ch) {
-        const endPos = pos++;
+      const startPos = pos;
+      stringLiteral(ch);
+      const endPos = ++pos;
+      ch = commentWhitespace();
+      if (ch === 58/*:*/) {
+        pos++;
         ch = commentWhitespace();
-        if (ch === 58/*:*/) {
-          pos++;
-          ch = commentWhitespace();
-          // nothing more complex than identifier expressions for now
-          if (!identifier()) {
-            pos = revertPos;
-            return;
-          }
-          ch = source.charCodeAt(pos);
-          addExport(source.slice(startPos, endPos));
+        // nothing more complex than identifier expressions for now
+        if (!identifier()) {
+          pos = revertPos;
+          return;
         }
+        ch = source.charCodeAt(pos);
+        _exports.add(decode(source.slice(startPos, endPos)));
       }
     }
     else {
@@ -1039,7 +1159,6 @@
     // import.meta
     case 46/*.*/:
       throw new Error('Unexpected import.meta in CJS module.');
-      return;
 
     default:
       // no space after "import" -> not an import keyword
@@ -1124,26 +1243,10 @@
   }
 }
 
-function singleQuoteString () {
-  while (pos++ < end) {
-    let ch = source.charCodeAt(pos);
-    if (ch === 39/*'*/)
-      return;
-    if (ch === 92/*\*/) {
-      ch = source.charCodeAt(++pos);
-      if (ch === 13/*\r*/ && source.charCodeAt(pos + 1) === 10/*\n*/)
-        pos++;
-    }
-    else if (isBr(ch))
-      break;
-  }
-  throw new Error('Unterminated string.');
-}
-
-function doubleQuoteString () {
+function stringLiteral (quote) {
   while (pos++ < end) {
     let ch = source.charCodeAt(pos);
-    if (ch === 34/*"*/)
+    if (ch === quote)
       return;
     if (ch === 92/*\*/) {
       ch = source.charCodeAt(++pos);
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/BUILD.gn nodejs-12.22.4~dfsg/deps/v8/BUILD.gn
--- nodejs-12.21.0~dfsg/deps/v8/BUILD.gn	2021-02-23 03:58:05.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/BUILD.gn	2021-07-29 12:35:23.000000000 +0200
@@ -6,7 +6,6 @@
 import("//build/config/arm.gni")
 import("//build/config/dcheck_always_on.gni")
 import("//build/config/host_byteorder.gni")
-import("//build/config/jumbo.gni")
 import("//build/config/mips.gni")
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build_overrides/build.gni")
@@ -266,7 +265,8 @@
 #
 
 config("internal_config_base") {
-  visibility = [ ":*" ]  # Only targets in this file can depend on this.
+ # Only targets in this file and its subdirs can depend on this.
+  visibility = [ "./*" ]
 
   include_dirs = [
     ".",
@@ -276,7 +276,8 @@
 
 config("internal_config") {
   defines = []
-  visibility = [ ":*" ]  # Only targets in this file can depend on this.
+  # Only targets in this file and its subdirs can depend on this.
+  visibility = [ "./*" ]
 
   configs = [
     "//build/config/compiler:wexit_time_destructors",
@@ -362,7 +363,8 @@
 # Put defines here that are only used in our internal files and NEVER in
 # external headers that embedders (such as chromium and node) might include.
 config("features") {
-  visibility = [ ":*" ]  # Only targets in this file can depend on this.
+  # Only targets in this file and its subdirs can depend on this.
+  visibility = [ "./*" ]
 
   defines = []
 
@@ -479,7 +481,8 @@
 }
 
 config("toolchain") {
-  visibility = [ ":*" ]  # Only targets in this file can depend on this.
+  # Only targets in this file and its subdirs can depend on this.
+  visibility = [ "./*" ]
 
   defines = []
   cflags = []
@@ -1470,17 +1473,12 @@
       if (v8_use_multi_snapshots) {
         deps += [ ":asm_to_inline_asm_trusted" ]
         sources += [ "$target_gen_dir/embedded_trusted.cc" ]
-        jumbo_excluded_sources = [ "$target_gen_dir/embedded_trusted.cc" ]
       }
     } else if (v8_enable_embedded_builtins) {
       sources += [ "$target_gen_dir/embedded.S" ]
 
       if (v8_use_multi_snapshots) {
         sources += [ "$target_gen_dir/embedded_trusted.S" ]
-        jumbo_excluded_sources = [
-          # Duplicated symbols with embedded.S
-          "$target_gen_dir/embedded_trusted.S",
-        ]
       }
     } else {
       sources += [ "src/snapshot/embedded/embedded-empty.cc" ]
@@ -1577,17 +1575,6 @@
     "src/interpreter/interpreter-intrinsics-generator.h",
   ]
 
-  jumbo_excluded_sources = [
-    # TODO(mostynb@vewd.com): don't exclude these http://crbug.com/752428
-    "src/builtins/builtins-async-iterator-gen.cc",
-    "src/builtins/builtins-async-generator-gen.cc",
-
-    # These source files take an unusually large amount of time to
-    # compile.  Build them separately to avoid bottlenecks.
-    "src/builtins/builtins-regexp-gen.cc",
-    "src/codegen/code-stub-assembler.cc",
-  ]
-
   if (v8_current_cpu == "x86") {
     sources += [
       ### gcmole(arch:ia32) ###
@@ -2996,19 +2983,6 @@
     sources += check_header_includes_sources
   }
 
-  jumbo_excluded_sources = [
-    # TODO(mostynb@vewd.com): don't exclude these http://crbug.com/752428
-    "src/profiler/heap-snapshot-generator.cc",  # Macro clash in mman-linux.h
-
-    # These source files take an unusually large amount of time to
-    # compile.  Build them separately to avoid bottlenecks.
-    "src/api/api.cc",
-    "src/heap/heap.cc",
-    "src/objects/elements.cc",
-    "src/objects/objects.cc",
-    "src/parsing/parser.cc",
-  ]
-
   if (v8_current_cpu == "x86") {
     sources += [  ### gcmole(arch:ia32) ###
       "src/codegen/ia32/assembler-ia32-inl.h",
@@ -3162,11 +3136,6 @@
         "src/diagnostics/unwinding-info-win64.h",
       ]
     }
-    jumbo_excluded_sources += [
-      # TODO(mostynb@vewd.com): fix this code so it doesn't need
-      # to be excluded, see the comments inside.
-      "src/codegen/arm64/instructions-arm64-constants.cc",
-    ]
   } else if (v8_current_cpu == "mips" || v8_current_cpu == "mipsel") {
     sources += [  ### gcmole(arch:mipsel) ###
       "src/codegen/mips/assembler-mips-inl.h",
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/DEPS nodejs-12.22.4~dfsg/deps/v8/DEPS
--- nodejs-12.21.0~dfsg/deps/v8/DEPS	2021-02-23 03:58:05.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/DEPS	2021-07-29 12:35:23.000000000 +0200
@@ -2,7 +2,15 @@
 # directory and assume that the root of the checkout is in ./v8/, so
 # all paths in here must match this assumption.
 
+gclient_gn_args_file = 'v8/build/config/gclient_args.gni'
+gclient_gn_args = [
+  'checkout_aemu'
+]
+
 vars = {
+  # By Default, do not checkout AEMU, as it is too big, as is done in Chromium.
+  'checkout_aemu': False,
+
   # Fetches only the SDK boot images which match at least one of the whitelist
   # entries in a comma-separated list.
   #
@@ -72,15 +80,15 @@
 
 deps = {
   'v8/build':
-    Var('chromium_url') + '/chromium/src/build.git' + '@' + '693faeda4ee025796c7e473d953a5a7b6ad64c93',
+    Var('chromium_url') + '/chromium/src/build.git' + '@' + 'c854b8178a7e0a20b168ffded4f2d2cb1e136e42',
   'v8/third_party/depot_tools':
-    Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + 'f38bc1796282c61087dcf15abc61b8fd18a68402',
+    Var('chromium_url') + '/chromium/tools/depot_tools.git' + '@' + 'd4e6fb6573e0955110a2c69be29557f6626d9ae6',
   'v8/third_party/icu':
     Var('chromium_url') + '/chromium/deps/icu.git' + '@' + '53f6b233a41ec982d8445996247093f7aaf41639',
   'v8/third_party/instrumented_libraries':
     Var('chromium_url') + '/chromium/src/third_party/instrumented_libraries.git' + '@' + 'b1c3ca20848c117eb935b02c25d441f03e6fbc5e',
   'v8/buildtools':
-    Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '74cfb57006f83cfe050817526db359d5c8a11628',
+    Var('chromium_url') + '/chromium/src/buildtools.git' + '@' + '6302c1175607a436e18947a5abe9df2209e845fc',
   'v8/buildtools/clang_format/script':
     Var('chromium_url') + '/chromium/llvm-project/cfe/tools/clang-format.git' + '@' + '96636aa0e9f047f17447f2d45a094d0b59ed7917',
   'v8/buildtools/linux64': {
@@ -104,11 +112,11 @@
     'condition': 'host_os == "mac"',
   },
   'v8/buildtools/third_party/libc++/trunk':
-    Var('chromium_url') + '/chromium/llvm-project/libcxx.git' + '@' + '5938e0582bac570a41edb3d6a2217c299adc1bc6',
+    Var('chromium_url') + '/chromium/llvm-project/libcxx.git' + '@' + '78d6a7767ed57b50122a161b91f59f19c9bd0d19',
   'v8/buildtools/third_party/libc++abi/trunk':
-    Var('chromium_url') + '/chromium/llvm-project/libcxxabi.git' + '@' + '0d529660e32d77d9111912d73f2c74fc5fa2a858',
+    Var('chromium_url') + '/chromium/llvm-project/libcxxabi.git' + '@' + 'ce3db128f9e4d6d19d1cdbe39bb45fcc64a5adb0',
   'v8/buildtools/third_party/libunwind/trunk':
-    Var('chromium_url') + '/external/llvm.org/libunwind.git' + '@' + '69d9b84cca8354117b9fe9705a4430d789ee599b',
+    Var('chromium_url') + '/external/llvm.org/libunwind.git' + '@' + '3e6ec2ae9afaa3683269b690612f84d907943ea2',
   'v8/buildtools/win': {
     'packages': [
       {
@@ -168,7 +176,7 @@
       'dep_type': 'cipd',
   },
   'v8/third_party/catapult': {
-    'url': Var('chromium_url') + '/catapult.git' + '@' + 'e7c719c3e85f76938bf4fef0ba37c27f89246f71',
+    'url': Var('chromium_url') + '/catapult.git' + '@' + 'f92a7636da65f28dad15bc524e6b681d1c311de0',
     'condition': 'checkout_android',
   },
   'v8/third_party/colorama/src': {
@@ -216,7 +224,7 @@
       'dep_type': 'cipd',
   },
   'v8/tools/clang':
-    Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + '2fef805e5b05b26a8c87c47865590b5f43218611',
+    Var('chromium_url') + '/chromium/src/tools/clang.git' + '@' + 'c72342ce992ebd9cc02c0d65f0af5941d29eb217',
   'v8/tools/luci-go': {
       'packages': [
         {
@@ -246,7 +254,7 @@
     'dep_type': 'cipd',
   },
   'v8/third_party/perfetto':
-    Var('android_url') + '/platform/external/perfetto.git' + '@' + '01615892494a9a8dc84414962d0a817bf97de2c2',
+    Var('android_url') + '/platform/external/perfetto.git' + '@' + '7cdc44f903d3bcfd1d0f67188bfa797a24756868',
   'v8/third_party/protobuf':
     Var('chromium_url') + '/external/github.com/google/protobuf'+ '@' + 'b68a347f56137b4b1a746e8c7438495a6ac1bd91',
 }
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/gni/proto_library.gni nodejs-12.22.4~dfsg/deps/v8/gni/proto_library.gni
--- nodejs-12.21.0~dfsg/deps/v8/gni/proto_library.gni	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/gni/proto_library.gni	2021-07-29 12:35:23.000000000 +0200
@@ -11,8 +11,6 @@
   assert(defined(invoker.sources))
   proto_sources = invoker.sources
 
-  set_sources_assignment_filter([])
-
   if (host_os == "win") {
     host_executable_suffix = ".exe"
   } else {
@@ -137,6 +135,12 @@
       ]
     }
 
+    if (defined(invoker.import_dirs)) {
+      foreach(path, invoker.import_dirs) {
+        args += [ "--import-dir=" + rebase_path(path, root_build_dir) ]
+      }
+    }
+
     if (generate_with_plugin) {
       plugin_path_rebased = rebase_path(plugin_path, root_build_dir)
       plugin_out_args = ""
@@ -187,10 +191,7 @@
                              "visibility",
                            ])
 
-    # Exclude the config.descriptor file which is an output for some reason.
-    set_sources_assignment_filter([ "*.descriptor" ])
     sources = get_target_outputs(":$action_name")
-    set_sources_assignment_filter(sources_assignment_filter)
 
     # configs -= [ "//gn/standalone:extra_warnings" ]
     if (defined(invoker.extra_configs)) {
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/gni/split_static_library.gni nodejs-12.22.4~dfsg/deps/v8/gni/split_static_library.gni
--- nodejs-12.21.0~dfsg/deps/v8/gni/split_static_library.gni	1970-01-01 01:00:00.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/gni/split_static_library.gni	2021-07-29 12:35:23.000000000 +0200
@@ -0,0 +1,78 @@
+# Copyright 2019 the V8 project authors. All rights reserved.
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/compiler/compiler.gni")
+
+template("split_static_library") {
+  assert(defined(invoker.split_count),
+         "Must define split_count for split_static_library")
+
+  # In many conditions the number of inputs will be 1 (because the
+  # count will be conditional on platform or configuration) and for
+  # some build configurations it's unnecessary to split libraries
+  # since the tooling will never create files of a problematic size.
+  if (invoker.split_count == 1 || use_lld) {
+    static_library(target_name) {
+      forward_variables_from(invoker, "*")
+    }
+  } else {
+    group_name = target_name
+
+    generated_static_libraries = []
+    current_library_index = 0
+    foreach(current_sources, split_list(invoker.sources, invoker.split_count)) {
+      current_name = "${target_name}_$current_library_index"
+      assert(
+          current_sources != [],
+          "Your values for splitting a static library generate one that has no sources.")
+      generated_static_libraries += [ ":$current_name" ]
+
+      static_library(current_name) {
+        # Generated static library shard gets everything but sources (which
+        # we're redefining) and visibility (which is set to be the group
+        # below).
+        forward_variables_from(invoker,
+                               "*",
+                               [
+                                 "check_includes",
+                                 "sources",
+                                 "visibility",
+                               ])
+        sources = current_sources
+        visibility = [ ":$group_name" ]
+
+        # When splitting a target's sources up into a series of static
+        # libraries, those targets will naturally include headers from each
+        # other arbitrarily. We could theoretically generate a web of
+        # dependencies and allow_circular_includes_from between all pairs of
+        # targets, but that's very cumbersome. Typical usage in Chrome is that
+        # only official Windows builds use split static libraries due to the
+        # Visual Studio size limits, and this means we'll still get header
+        # checking coverage for the other configurations.
+        check_includes = false
+
+        # Uniquify the output name if one is specified.
+        if (defined(invoker.output_name)) {
+          output_name = "${invoker.output_name}_$current_library_index"
+        }
+      }
+
+      current_library_index = current_library_index + 1
+    }
+
+    group(group_name) {
+      public_deps = generated_static_libraries
+      forward_variables_from(invoker,
+                             [
+                               "testonly",
+                               "visibility",
+                             ])
+    }
+  }
+}
+
+set_defaults("split_static_library") {
+  configs = default_compiler_configs
+}
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/gni/v8.gni nodejs-12.22.4~dfsg/deps/v8/gni/v8.gni
--- nodejs-12.21.0~dfsg/deps/v8/gni/v8.gni	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/gni/v8.gni	2021-07-29 12:35:23.000000000 +0200
@@ -2,10 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/jumbo.gni")
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build/config/v8_target_cpu.gni")
-import("//build/split_static_library.gni")
+import("split_static_library.gni")
 
 declare_args() {
   # Set flags for tracking code coverage. Uses gcov with gcc and sanitizer
@@ -80,7 +79,7 @@
   # build configuration. This allows us to set v8_use_multi_snapshots=true on
   # all bots, and e.g. no-snapshot bots will automatically do the right thing.
   v8_use_multi_snapshots =
-      v8_use_external_startup_data && !build_with_chromium && !use_jumbo_build
+      v8_use_external_startup_data && !build_with_chromium
 }
 
 if (v8_enable_backtrace == "") {
@@ -149,9 +148,9 @@
       defined(v8_static_library) && v8_static_library && is_win) {
     link_target_type = "jumbo_split_static_library"
   } else if (defined(v8_static_library) && v8_static_library) {
-    link_target_type = "jumbo_static_library"
+    link_target_type = "static_library"
   } else {
-    link_target_type = "jumbo_source_set"
+    link_target_type = "source_set"
   }
   target(link_target_type, target_name) {
     forward_variables_from(invoker,
@@ -170,7 +169,7 @@
 }
 
 template("v8_header_set") {
-  jumbo_source_set(target_name) {
+  source_set(target_name) {
     forward_variables_from(invoker, "*", [ "configs" ])
     configs -= v8_remove_configs
     configs += v8_add_configs
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/infra/mb/mb_config.pyl nodejs-12.22.4~dfsg/deps/v8/infra/mb/mb_config.pyl
--- nodejs-12.21.0~dfsg/deps/v8/infra/mb/mb_config.pyl	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/infra/mb/mb_config.pyl	2021-07-29 12:35:23.000000000 +0200
@@ -64,11 +64,6 @@
       'V8 Linux64 - debug - header includes': 'debug_x64_header_includes',
       'V8 Linux64 - shared': 'release_x64_shared_verify_heap',
       'V8 Linux64 - verify csa': 'release_x64_verify_csa',
-      # Jumbo.
-      'V8 Linux64 Jumbo': 'release_x64_jumbo',
-      'V8 Linux64 Jumbo - debug': 'debug_x64_jumbo',
-      'V8 Linux64 Jumbo - limited': 'release_x64_jumbo_limited',
-      'V8 Linux64 Jumbo - limited - debug': 'debug_x64_jumbo_limited',
       # Windows.
       'V8 Win32 - builder': 'release_x86_minimal_symbols',
       'V8 Win32 - debug builder': 'debug_x86_minimal_symbols',
@@ -230,8 +225,6 @@
       'v8_linux64_msan_rel': 'release_simulate_arm64_msan_minimal_symbols',
       'v8_linux64_sanitizer_coverage_rel':
           'release_x64_asan_minimal_symbols_coverage',
-      'v8_linux64_jumbo_compile_rel': 'release_x64_jumbo_trybot',
-      'v8_linux64_jumbo_limited_compile_rel': 'release_x64_jumbo_limited_trybot',
       'v8_linux64_tsan_rel': 'release_x64_tsan_minimal_symbols',
       'v8_linux64_tsan_isolates_rel_ng':
           'release_x64_tsan_minimal_symbols',
@@ -448,14 +441,6 @@
       'release_bot', 'x64', 'ios_simulator'],
     'release_x64_internal': [
       'release_bot', 'x64', 'v8_snapshot_internal'],
-    'release_x64_jumbo': [
-      'release_bot', 'x64', 'jumbo'],
-    'release_x64_jumbo_trybot': [
-      'release_trybot', 'x64', 'jumbo'],
-    'release_x64_jumbo_limited': [
-      'release_bot', 'x64', 'jumbo_limited'],
-    'release_x64_jumbo_limited_trybot': [
-      'release_trybot', 'x64', 'jumbo_limited'],
     'release_x64_minimal_symbols': [
       'release_bot', 'x64', 'minimal_symbols'],
     'release_x64_pointer_compression': [
@@ -499,10 +484,6 @@
       'debug_bot', 'x64', 'gcc', 'v8_check_header_includes'],
     'debug_x64_header_includes': [
       'debug_bot', 'x64', 'v8_check_header_includes'],
-    'debug_x64_jumbo': [
-      'debug_bot', 'x64', 'jumbo'],
-    'debug_x64_jumbo_limited': [
-      'debug_bot', 'x64', 'jumbo_limited'],
     'debug_x64_minimal_symbols': [
       'debug_bot', 'x64', 'minimal_symbols'],
     'debug_x64_perfetto': [
@@ -668,14 +649,6 @@
       'gn_args': 'target_cpu="x64" target_os="ios"',
     },
 
-    'jumbo': {
-      'gn_args': 'use_jumbo_build=true',
-    },
-
-    'jumbo_limited': {
-      'gn_args': 'use_jumbo_build=true jumbo_file_merge_limit=50',
-    },
-
     'lsan': {
       'mixins': ['v8_enable_test_features'],
       'gn_args': 'is_lsan=true',
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/base/cpu.cc nodejs-12.22.4~dfsg/deps/v8/src/base/cpu.cc
--- nodejs-12.21.0~dfsg/deps/v8/src/base/cpu.cc	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/base/cpu.cc	2021-07-29 12:35:23.000000000 +0200
@@ -27,6 +27,9 @@
 #ifndef POWER_9
 #define POWER_9 0x20000
 #endif
+#ifndef POWER_10
+#define POWER_10 0x40000
+#endif
 #endif
 #if V8_OS_POSIX
 #include <unistd.h>  // sysconf()
@@ -639,7 +642,10 @@
 
   part_ = -1;
   if (auxv_cpu_type) {
-    if (strcmp(auxv_cpu_type, "power9") == 0) {
+    if (strcmp(auxv_cpu_type, "power10") == 0) {
+      part_ = PPC_POWER10;
+    }
+    else if (strcmp(auxv_cpu_type, "power9") == 0) {
       part_ = PPC_POWER9;
     } else if (strcmp(auxv_cpu_type, "power8") == 0) {
       part_ = PPC_POWER8;
@@ -660,6 +666,9 @@
 
 #elif V8_OS_AIX
   switch (_system_configuration.implementation) {
+    case POWER_10:
+      part_ = PPC_POWER10;
+      break;
     case POWER_9:
       part_ = PPC_POWER9;
       break;
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/base/cpu.h nodejs-12.22.4~dfsg/deps/v8/src/base/cpu.h
--- nodejs-12.21.0~dfsg/deps/v8/src/base/cpu.h	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/base/cpu.h	2021-07-29 12:35:23.000000000 +0200
@@ -70,6 +70,7 @@
     PPC_POWER7,
     PPC_POWER8,
     PPC_POWER9,
+    PPC_POWER10,
     PPC_G4,
     PPC_G5,
     PPC_PA6T
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/base/macros.h nodejs-12.22.4~dfsg/deps/v8/src/base/macros.h
--- nodejs-12.21.0~dfsg/deps/v8/src/base/macros.h	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/base/macros.h	2021-07-29 12:35:23.000000000 +0200
@@ -357,14 +357,14 @@
   STATIC_ASSERT(std::is_integral<T>::value);
   // m must be a power of two.
   DCHECK(m != 0 && ((m & (m - 1)) == 0));
-  return x & -m;
+  return x & static_cast<T>(-m);
 }
 template <intptr_t m, typename T>
 constexpr inline T RoundDown(T x) {
   STATIC_ASSERT(std::is_integral<T>::value);
   // m must be a power of two.
   STATIC_ASSERT(m != 0 && ((m & (m - 1)) == 0));
-  return x & -m;
+  return x & static_cast<T>(-m);
 }
 
 // Return the smallest multiple of m which is >= x.
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/codegen/ppc/assembler-ppc.cc nodejs-12.22.4~dfsg/deps/v8/src/codegen/ppc/assembler-ppc.cc
--- nodejs-12.21.0~dfsg/deps/v8/src/codegen/ppc/assembler-ppc.cc	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/codegen/ppc/assembler-ppc.cc	2021-07-29 12:35:23.000000000 +0200
@@ -67,21 +67,28 @@
 #ifndef USE_SIMULATOR
   // Probe for additional features at runtime.
   base::CPU cpu;
-  if (cpu.part() == base::CPU::PPC_POWER9) {
+  if (cpu.part() == base::CPU::PPC_POWER9 || 
+      cpu.part() == base::CPU::PPC_POWER10) {
     supported_ |= (1u << MODULO);
   }
 #if V8_TARGET_ARCH_PPC64
-  if (cpu.part() == base::CPU::PPC_POWER8) {
+  if (cpu.part() == base::CPU::PPC_POWER8 || 
+      cpu.part() == base::CPU::PPC_POWER9 || 
+      cpu.part() == base::CPU::PPC_POWER10) {
     supported_ |= (1u << FPR_GPR_MOV);
   }
 #endif
   if (cpu.part() == base::CPU::PPC_POWER6 ||
       cpu.part() == base::CPU::PPC_POWER7 ||
-      cpu.part() == base::CPU::PPC_POWER8) {
+      cpu.part() == base::CPU::PPC_POWER8 || 
+      cpu.part() == base::CPU::PPC_POWER9 || 
+      cpu.part() == base::CPU::PPC_POWER10) {
     supported_ |= (1u << LWSYNC);
   }
   if (cpu.part() == base::CPU::PPC_POWER7 ||
-      cpu.part() == base::CPU::PPC_POWER8) {
+      cpu.part() == base::CPU::PPC_POWER8 || 
+      cpu.part() == base::CPU::PPC_POWER9 || 
+      cpu.part() == base::CPU::PPC_POWER10) {
     supported_ |= (1u << ISELECT);
     supported_ |= (1u << VSX);
   }
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/objects/js-list-format.cc nodejs-12.22.4~dfsg/deps/v8/src/objects/js-list-format.cc
--- nodejs-12.21.0~dfsg/deps/v8/src/objects/js-list-format.cc	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/objects/js-list-format.cc	2021-07-29 12:35:23.000000000 +0200
@@ -24,11 +24,14 @@
 #include "unicode/fpositer.h"
 #include "unicode/listformatter.h"
 #include "unicode/ulistformatter.h"
+#include "unicode/uvernum.h"
 
 namespace v8 {
 namespace internal {
 
 namespace {
+
+#if U_ICU_VERSION_MAJOR_NUM < 67
 const char* kStandard = "standard";
 const char* kOr = "or";
 const char* kUnit = "unit";
@@ -72,6 +75,31 @@
   }
   UNREACHABLE();
 }
+#else
+UListFormatterWidth GetIcuWidth(JSListFormat::Style style) {
+  switch (style) {
+    case JSListFormat::Style::LONG:
+      return ULISTFMT_WIDTH_WIDE;
+    case JSListFormat::Style::SHORT:
+      return ULISTFMT_WIDTH_SHORT;
+    case JSListFormat::Style::NARROW:
+      return ULISTFMT_WIDTH_NARROW;
+  }
+  UNREACHABLE();
+}
+
+UListFormatterType GetIcuType(JSListFormat::Type type) {
+  switch (type) {
+    case JSListFormat::Type::CONJUNCTION:
+      return ULISTFMT_TYPE_AND;
+    case JSListFormat::Type::DISJUNCTION:
+      return ULISTFMT_TYPE_OR;
+    case JSListFormat::Type::UNIT:
+      return ULISTFMT_TYPE_UNITS;
+  }
+  UNREACHABLE();
+}
+#endif
 
 }  // namespace
 
@@ -170,7 +198,11 @@
   icu::Locale icu_locale = r.icu_locale;
   UErrorCode status = U_ZERO_ERROR;
   icu::ListFormatter* formatter = icu::ListFormatter::createInstance(
+#if U_ICU_VERSION_MAJOR_NUM < 67
       icu_locale, GetIcuStyleString(style_enum, type_enum), status);
+#else
+      icu_locale, GetIcuType(type_enum), GetIcuWidth(style_enum), status);
+#endif
   if (U_FAILURE(status)) {
     delete formatter;
     FATAL("Failed to create ICU list formatter, are ICU data files missing?");
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/src/profiler/profiler-listener.cc nodejs-12.22.4~dfsg/deps/v8/src/profiler/profiler-listener.cc
--- nodejs-12.21.0~dfsg/deps/v8/src/profiler/profiler-listener.cc	2021-02-23 03:58:06.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/src/profiler/profiler-listener.cc	2021-07-29 12:35:23.000000000 +0200
@@ -120,7 +120,8 @@
     // profiler as is stored on the code object, except that we transform source
     // positions to line numbers here, because we only care about attributing
     // ticks to a given line.
-    for (SourcePositionTableIterator it(abstract_code.source_position_table());
+    for (SourcePositionTableIterator it(
+             handle(abstract_code.source_position_table(), isolate_));
          !it.done(); it.Advance()) {
       int position = it.source_position().ScriptOffset();
       int inlining_id = it.source_position().InliningId();
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/deps/v8/testing/gtest/BUILD.gn nodejs-12.22.4~dfsg/deps/v8/testing/gtest/BUILD.gn
--- nodejs-12.21.0~dfsg/deps/v8/testing/gtest/BUILD.gn	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/deps/v8/testing/gtest/BUILD.gn	2021-07-29 12:35:25.000000000 +0200
@@ -4,9 +4,9 @@
 
 import("//build_overrides/gtest.gni")
 if (is_ios) {
+  import("//build/buildflag_header.gni")
   import("//build/config/coverage/coverage.gni")
   import("//build/config/ios/ios_sdk.gni")
-  import("//build/buildflag_header.gni")
 }
 
 config("gtest_direct_config") {
@@ -40,9 +40,7 @@
     #    Android. https://codereview.chromium.org/2852613002/#ps20001
     "empty.cc",
   ]
-  public_deps = [
-    "//third_party/googletest:gtest",
-  ]
+  public_deps = [ "//third_party/googletest:gtest" ]
 
   public_configs = [ ":gtest_direct_config" ]
 
@@ -58,9 +56,6 @@
   }
 
   if ((is_mac || is_ios) && gtest_include_objc_support) {
-    if (is_ios) {
-      set_sources_assignment_filter([])
-    }
     sources += [
       "../gtest_mac.h",
       "../gtest_mac.mm",
@@ -68,7 +63,6 @@
     if (gtest_include_platform_test) {
       sources += [ "../platform_test_mac.mm" ]
     }
-    set_sources_assignment_filter(sources_assignment_filter)
   }
 
   if (is_ios && gtest_include_ios_coverage) {
@@ -76,9 +70,7 @@
       "../coverage_util_ios.h",
       "../coverage_util_ios.mm",
     ]
-    deps = [
-      ":ios_enable_coverage",
-    ]
+    deps = [ ":ios_enable_coverage" ]
   }
 }
 
@@ -87,9 +79,7 @@
 # into //third_party/googletest.
 source_set("gtest_main") {
   testonly = true
-  deps = [
-    "//third_party/googletest:gtest_main",
-  ]
+  deps = [ "//third_party/googletest:gtest_main" ]
 }
 
 if (is_ios) {
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/modules/esm/get_source.js nodejs-12.22.4~dfsg/lib/internal/modules/esm/get_source.js
--- nodejs-12.21.0~dfsg/lib/internal/modules/esm/get_source.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/modules/esm/get_source.js	2021-07-29 12:35:25.000000000 +0200
@@ -1,5 +1,8 @@
 'use strict';
 
+const {
+  decodeURIComponent,
+} = primordials;
 const { getOptionValue } = require('internal/options');
 const manifest = getOptionValue('--experimental-policy') ?
   require('internal/process/policy').manifest :
@@ -28,8 +31,8 @@
     if (!match) {
       throw new ERR_INVALID_URL(url);
     }
-    const [ , base64, body ] = match;
-    source = Buffer.from(body, base64 ? 'base64' : 'utf8');
+    const { 1: base64, 2: body } = match;
+    source = Buffer.from(decodeURIComponent(body), base64 ? 'base64' : 'utf8');
   } else {
     throw new ERR_INVALID_URL_SCHEME(['file', 'data']);
   }
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/modules/esm/resolve.js nodejs-12.22.4~dfsg/lib/internal/modules/esm/resolve.js
--- nodejs-12.21.0~dfsg/lib/internal/modules/esm/resolve.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/modules/esm/resolve.js	2021-07-29 12:35:25.000000000 +0200
@@ -30,7 +30,7 @@
   Stats,
 } = require('fs');
 const { getOptionValue } = require('internal/options');
-const { sep, relative } = require('path');
+const { sep, relative, resolve } = require('path');
 const preserveSymlinks = getOptionValue('--preserve-symlinks');
 const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
 const typeFlag = getOptionValue('--input-type');
@@ -160,16 +160,18 @@
   return packageConfig;
 }
 
-/*
+/**
  * Legacy CommonJS main resolution:
  * 1. let M = pkg_url + (json main field)
  * 2. TRY(M, M.js, M.json, M.node)
  * 3. TRY(M/index.js, M/index.json, M/index.node)
  * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
  * 5. NOT_FOUND
+ * @param {string | URL} url
+ * @returns {boolean}
  */
 function fileExists(url) {
-  return tryStatSync(fileURLToPath(url)).isFile();
+  return tryStatSync(url).isFile();
 }
 
 function legacyMainResolve(packageJSONUrl, packageConfig, base) {
@@ -236,7 +238,19 @@
   return undefined;
 }
 
-function resolveIndex(search) {
+function resolveDirectoryEntry(search) {
+  const dirPath = fileURLToPath(search);
+  const pkgJsonPath = resolve(dirPath, 'package.json');
+  if (fileExists(pkgJsonPath)) {
+    const pkgJson = packageJsonReader.read(pkgJsonPath);
+    if (pkgJson.containsKeys) {
+      const { main } = JSONParse(pkgJson.string);
+      if (main != null) {
+        const mainUrl = pathToFileURL(resolve(dirPath, main));
+        return resolveExtensionsWithTryExactName(mainUrl);
+      }
+    }
+  }
   return resolveExtensions(new URL('index', search));
 }
 
@@ -252,10 +266,10 @@
     let file = resolveExtensionsWithTryExactName(resolved);
     if (file !== undefined) return file;
     if (!StringPrototypeEndsWith(path, '/')) {
-      file = resolveIndex(new URL(`${resolved}/`));
+      file = resolveDirectoryEntry(new URL(`${resolved}/`));
       if (file !== undefined) return file;
     } else {
-      return resolveIndex(resolved) || resolved;
+      return resolveDirectoryEntry(resolved) || resolved;
     }
     throw new ERR_MODULE_NOT_FOUND(
       resolved.pathname, fileURLToPath(base), 'module');
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/per_context/primordials.js nodejs-12.22.4~dfsg/lib/internal/per_context/primordials.js
--- nodejs-12.21.0~dfsg/lib/internal/per_context/primordials.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/per_context/primordials.js	2021-07-29 12:35:25.000000000 +0200
@@ -106,6 +106,16 @@
   class SafePromise extends Promise {}
 );
 
+// Create copies of URI handling functions
+[
+  decodeURI,
+  decodeURIComponent,
+  encodeURI,
+  encodeURIComponent,
+].forEach((fn) => {
+  primordials[fn.name] = fn;
+});
+
 // Create copies of the namespace objects
 [
   'JSON',
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/url.js nodejs-12.22.4~dfsg/lib/internal/url.js
--- nodejs-12.21.0~dfsg/lib/internal/url.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/url.js	2021-07-29 12:35:25.000000000 +0200
@@ -14,6 +14,7 @@
   Symbol,
   SymbolIterator,
   SymbolToStringTag,
+  decodeURIComponent,
 } = primordials;
 
 const { inspect } = require('internal/util/inspect');
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/internal/worker.js nodejs-12.22.4~dfsg/lib/internal/worker.js
--- nodejs-12.21.0~dfsg/lib/internal/worker.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/internal/worker.js	2021-07-29 12:35:25.000000000 +0200
@@ -17,6 +17,7 @@
 const EventEmitter = require('events');
 const assert = require('internal/assert');
 const path = require('path');
+const { timeOrigin } = internalBinding('performance');
 
 const errorCodes = require('internal/errors').codes;
 const {
@@ -67,6 +68,8 @@
 const kOnCouldNotSerializeErr = Symbol('kOnCouldNotSerializeErr');
 const kOnErrorMessage = Symbol('kOnErrorMessage');
 const kParentSideStdio = Symbol('kParentSideStdio');
+const kLoopStartTime = Symbol('kLoopStartTime');
+const kIsOnline = Symbol('kIsOnline');
 
 const SHARE_ENV = SymbolFor('nodejs.worker_threads.SHARE_ENV');
 let debug = require('internal/util/debuglog').debuglog('worker', (fn) => {
@@ -214,6 +217,12 @@
         null,
       hasStdin: !!options.stdin
     }, transferList);
+    // Use this to cache the Worker's loopStart value once available.
+    this[kLoopStartTime] = -1;
+    this[kIsOnline] = false;
+    this.performance = {
+      eventLoopUtilization: eventLoopUtilization.bind(this),
+    };
     // Actually start the new thread now that everything is in place.
     this[kHandle].startThread();
   }
@@ -245,6 +254,7 @@
   [kOnMessage](message) {
     switch (message.type) {
       case messageTypes.UP_AND_RUNNING:
+        this[kIsOnline] = true;
         return this.emit('online');
       case messageTypes.COULD_NOT_SERIALIZE_ERROR:
         return this[kOnCouldNotSerializeErr]();
@@ -406,6 +416,52 @@
   };
 }
 
+function eventLoopUtilization(util1, util2) {
+  // TODO(trevnorris): Works to solve the thread-safe read/write issue of
+  // loopTime, but has the drawback that it can't be set until the event loop
+  // has had a chance to turn. So it will be impossible to read the ELU of
+  // a worker thread immediately after it's been created.
+  if (!this[kIsOnline] || !this[kHandle]) {
+    return { idle: 0, active: 0, utilization: 0 };
+  }
+
+  // Cache loopStart, since it's only written to once.
+  if (this[kLoopStartTime] === -1) {
+    this[kLoopStartTime] = this[kHandle].loopStartTime();
+    if (this[kLoopStartTime] === -1)
+      return { idle: 0, active: 0, utilization: 0 };
+  }
+
+  if (util2) {
+    const idle = util1.idle - util2.idle;
+    const active = util1.active - util2.active;
+    return { idle, active, utilization: active / (idle + active) };
+  }
+
+  const idle = this[kHandle].loopIdleTime();
+
+  // Using performance.now() here is fine since it's always the time from
+  // the beginning of the process, and is why it needs to be offset by the
+  // loopStart time (which is also calculated from the beginning of the
+  // process).
+  const active = now() - this[kLoopStartTime] - idle;
+
+  if (!util1) {
+    return { idle, active, utilization: active / (idle + active) };
+  }
+
+  const idle_delta = idle - util1.idle;
+  const active_delta = active - util1.active;
+  const utilization = active_delta / (idle_delta + active_delta);
+  return { idle: idle_delta, active: active_delta, utilization };
+}
+
+// Duplicate code from performance.now() so don't need to require perf_hooks.
+function now() {
+  const hr = process.hrtime();
+  return (hr[0] * 1000 + hr[1] / 1e6) - timeOrigin;
+}
+
 module.exports = {
   ownsProcessState,
   isMainThread,
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/querystring.js nodejs-12.22.4~dfsg/lib/querystring.js
--- nodejs-12.21.0~dfsg/lib/querystring.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/querystring.js	2021-07-29 12:35:25.000000000 +0200
@@ -29,6 +29,7 @@
   MathAbs,
   ObjectCreate,
   ObjectKeys,
+  decodeURIComponent,
 } = primordials;
 
 const { Buffer } = require('buffer');
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/url.js nodejs-12.22.4~dfsg/lib/url.js
--- nodejs-12.21.0~dfsg/lib/url.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/url.js	2021-07-29 12:35:25.000000000 +0200
@@ -25,6 +25,7 @@
   ObjectCreate,
   ObjectKeys,
   SafeSet,
+  decodeURIComponent,
 } = primordials;
 
 const { toASCII } = require('internal/idna');
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/lib/v8.js nodejs-12.22.4~dfsg/lib/v8.js
--- nodejs-12.21.0~dfsg/lib/v8.js	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/lib/v8.js	2021-07-29 12:35:25.000000000 +0200
@@ -37,6 +37,12 @@
   Serializer: _Serializer,
   Deserializer: _Deserializer
 } = internalBinding('serdes');
+
+let profiler = {};
+if (internalBinding('config').hasInspector) {
+  profiler = internalBinding('profiler');
+}
+
 const assert = require('internal/assert');
 const { copy } = internalBinding('buffer');
 const { inspect } = require('internal/util/inspect');
@@ -286,6 +292,8 @@
   DefaultSerializer,
   DefaultDeserializer,
   deserialize,
+  takeCoverage: profiler.takeCoverage,
+  stopCoverage: profiler.stopCoverage,
   serialize,
   writeHeapSnapshot,
 };
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/api/environment.cc nodejs-12.22.4~dfsg/src/api/environment.cc
--- nodejs-12.21.0~dfsg/src/api/environment.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/api/environment.cc	2021-07-29 12:35:25.000000000 +0200
@@ -712,7 +712,8 @@
 }
 
 void DefaultProcessExitHandler(Environment* env, int exit_code) {
-  Stop(env);
+  env->set_can_call_into_js(false);
+  env->stop_sub_worker_contexts();
   DisposePlatform();
   uv_library_shutdown();
   exit(exit_code);
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/cares_wrap.cc nodejs-12.22.4~dfsg/src/cares_wrap.cc
--- nodejs-12.21.0~dfsg/src/cares_wrap.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/cares_wrap.cc	2021-07-29 12:35:25.000000000 +0200
@@ -49,7 +49,11 @@
 # include <arpa/nameser.h>
 #endif
 
-#if defined(__OpenBSD__)
+// OpenBSD does not define these
+#ifndef AI_ALL
+# define AI_ALL 0
+#endif
+#ifndef AI_V4MAPPED
 # define AI_V4MAPPED 0
 #endif
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/env.cc nodejs-12.22.4~dfsg/src/env.cc
--- nodejs-12.21.0~dfsg/src/env.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/env.cc	2021-07-29 12:35:25.000000000 +0200
@@ -550,10 +550,9 @@
   }
 }
 
-void Environment::Stop() {
+void Environment::ExitEnv() {
   set_can_call_into_js(false);
   set_stopping(true);
-  stop_sub_worker_contexts();
   isolate_->TerminateExecution();
   SetImmediateThreadsafe([](Environment* env) { uv_stop(env->event_loop()); });
 }
@@ -1039,6 +1038,8 @@
 }
 
 void Environment::stop_sub_worker_contexts() {
+  DCHECK_EQ(Isolate::GetCurrent(), isolate());
+
   while (!sub_worker_contexts_.empty()) {
     Worker* w = *sub_worker_contexts_.begin();
     remove_sub_worker_context(w);
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/env.h nodejs-12.22.4~dfsg/src/env.h
--- nodejs-12.21.0~dfsg/src/env.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/env.h	2021-07-29 12:35:25.000000000 +0200
@@ -253,6 +253,7 @@
   V(fd_string, "fd")                                                           \
   V(fields_string, "fields")                                                   \
   V(file_string, "file")                                                       \
+  V(filename_string, "filename")                                               \
   V(fingerprint256_string, "fingerprint256")                                   \
   V(fingerprint_string, "fingerprint")                                         \
   V(flags_string, "flags")                                                     \
@@ -926,7 +927,7 @@
   void RegisterHandleCleanups();
   void CleanupHandles();
   void Exit(int code);
-  void Stop();
+  void ExitEnv();
 
   // Register clean-up cb to be called on environment destruction.
   inline void RegisterHandleCleanup(uv_handle_t* handle,
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/inspector_profiler.cc nodejs-12.22.4~dfsg/src/inspector_profiler.cc
--- nodejs-12.21.0~dfsg/src/inspector_profiler.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/inspector_profiler.cc	2021-07-29 12:35:25.000000000 +0200
@@ -9,6 +9,7 @@
 #include "util-inl.h"
 #include "v8-inspector.h"
 
+#include <cinttypes>
 #include <sstream>
 
 namespace node {
@@ -36,10 +37,11 @@
           false)),
       env_(env) {}
 
-size_t V8ProfilerConnection::DispatchMessage(const char* method,
-                                             const char* params) {
+uint32_t V8ProfilerConnection::DispatchMessage(const char* method,
+                                               const char* params,
+                                               bool is_profile_request) {
   std::stringstream ss;
-  size_t id = next_id();
+  uint32_t id = next_id();
   ss << R"({ "id": )" << id;
   DCHECK(method != nullptr);
   ss << R"(, "method": ")" << method << '"';
@@ -50,12 +52,15 @@
   std::string message = ss.str();
   const uint8_t* message_data =
       reinterpret_cast<const uint8_t*>(message.c_str());
+  // Save the id of the profile request to identify its response.
+  if (is_profile_request) {
+    profile_ids_.insert(id);
+  }
   Debug(env(),
         DebugCategory::INSPECTOR_PROFILER,
         "Dispatching message %s\n",
         message.c_str());
   session_->Dispatch(StringView(message_data, message.length()));
-  // TODO(joyeecheung): use this to identify the ending message.
   return id;
 }
 
@@ -77,21 +82,10 @@
   Environment* env = connection_->env();
   Isolate* isolate = env->isolate();
   HandleScope handle_scope(isolate);
-  Context::Scope context_scope(env->context());
+  Local<Context> context = env->context();
+  Context::Scope context_scope(context);
 
-  // TODO(joyeecheung): always parse the message so that we can use the id to
-  // identify ending messages as well as printing the message in the debug
-  // output when there is an error.
   const char* type = connection_->type();
-  Debug(env,
-        DebugCategory::INSPECTOR_PROFILER,
-        "Receive %s profile message, ending = %s\n",
-        type,
-        connection_->ending() ? "true" : "false");
-  if (!connection_->ending()) {
-    return;
-  }
-
   // Convert StringView to a Local<String>.
   Local<String> message_str;
   if (!String::NewFromTwoByte(isolate,
@@ -99,11 +93,62 @@
                               NewStringType::kNormal,
                               message.length())
            .ToLocal(&message_str)) {
-    fprintf(stderr, "Failed to convert %s profile message\n", type);
+    fprintf(
+        stderr, "Failed to convert %s profile message to V8 string\n", type);
+    return;
+  }
+
+  Debug(env,
+        DebugCategory::INSPECTOR_PROFILER,
+        "Receive %s profile message\n",
+        type);
+
+  Local<Value> parsed;
+  if (!v8::JSON::Parse(context, message_str).ToLocal(&parsed) ||
+      !parsed->IsObject()) {
+    fprintf(stderr, "Failed to parse %s profile result as JSON object\n", type);
+    return;
+  }
+
+  Local<Object> response = parsed.As<Object>();
+  Local<Value> id_v;
+  if (!response->Get(context, FIXED_ONE_BYTE_STRING(isolate, "id"))
+           .ToLocal(&id_v) ||
+      !id_v->IsUint32()) {
+    Utf8Value str(isolate, message_str);
+    fprintf(
+        stderr, "Cannot retrieve id from the response message:\n%s\n", *str);
     return;
   }
+  uint32_t id = id_v.As<v8::Uint32>()->Value();
 
-  connection_->WriteProfile(message_str);
+  if (!connection_->HasProfileId(id)) {
+    Utf8Value str(isolate, message_str);
+    Debug(env, DebugCategory::INSPECTOR_PROFILER, "%s\n", *str);
+    return;
+  } else {
+    Debug(env,
+          DebugCategory::INSPECTOR_PROFILER,
+          "Writing profile response (id = %" PRIu64 ")\n",
+          static_cast<uint64_t>(id));
+  }
+
+  // Get message.result from the response.
+  Local<Value> result_v;
+  if (!response->Get(context, FIXED_ONE_BYTE_STRING(isolate, "result"))
+           .ToLocal(&result_v)) {
+    fprintf(stderr, "Failed to get 'result' from %s profile response\n", type);
+    return;
+  }
+
+  if (!result_v->IsObject()) {
+    fprintf(
+        stderr, "'result' from %s profile response is not an object\n", type);
+    return;
+  }
+
+  connection_->WriteProfile(result_v.As<Object>());
+  connection_->RemoveProfileId(id);
 }
 
 static bool EnsureDirectory(const std::string& directory, const char* type) {
@@ -138,45 +183,9 @@
   return filename;
 }
 
-static MaybeLocal<Object> ParseProfile(Environment* env,
-                                       Local<String> message,
-                                       const char* type) {
-  Local<Context> context = env->context();
-  Isolate* isolate = env->isolate();
-
-  // Get message.result from the response
-  Local<Value> parsed;
-  if (!v8::JSON::Parse(context, message).ToLocal(&parsed) ||
-      !parsed->IsObject()) {
-    fprintf(stderr, "Failed to parse %s profile result as JSON object\n", type);
-    return MaybeLocal<Object>();
-  }
-
-  Local<Value> result_v;
-  if (!parsed.As<Object>()
-           ->Get(context, FIXED_ONE_BYTE_STRING(isolate, "result"))
-           .ToLocal(&result_v)) {
-    fprintf(stderr, "Failed to get 'result' from %s profile message\n", type);
-    return MaybeLocal<Object>();
-  }
-
-  if (!result_v->IsObject()) {
-    fprintf(
-        stderr, "'result' from %s profile message is not an object\n", type);
-    return MaybeLocal<Object>();
-  }
-
-  return result_v.As<Object>();
-}
-
-void V8ProfilerConnection::WriteProfile(Local<String> message) {
+void V8ProfilerConnection::WriteProfile(Local<Object> result) {
   Local<Context> context = env_->context();
 
-  // Get message.result from the response.
-  Local<Object> result;
-  if (!ParseProfile(env_, message, type()).ToLocal(&result)) {
-    return;
-  }
   // Generate the profile output from the subclass.
   Local<Object> profile;
   if (!GetProfile(result).ToLocal(&profile)) {
@@ -203,7 +212,7 @@
   WriteResult(env_, path.c_str(), result_s);
 }
 
-void V8CoverageConnection::WriteProfile(Local<String> message) {
+void V8CoverageConnection::WriteProfile(Local<Object> result) {
   Isolate* isolate = env_->isolate();
   Local<Context> context = env_->context();
   HandleScope handle_scope(isolate);
@@ -219,11 +228,6 @@
     return;
   }
 
-  // Get message.result from the response.
-  Local<Object> result;
-  if (!ParseProfile(env_, message, type()).ToLocal(&result)) {
-    return;
-  }
   // Generate the profile output from the subclass.
   Local<Object> profile;
   if (!GetProfile(result).ToLocal(&profile)) {
@@ -287,10 +291,23 @@
                   R"({ "callCount": true, "detailed": true })");
 }
 
+void V8CoverageConnection::TakeCoverage() {
+  DispatchMessage("Profiler.takePreciseCoverage", nullptr, true);
+}
+
+void V8CoverageConnection::StopCoverage() {
+  DispatchMessage("Profiler.stopPreciseCoverage");
+}
+
 void V8CoverageConnection::End() {
-  CHECK_EQ(ending_, false);
+  Debug(env_,
+      DebugCategory::INSPECTOR_PROFILER,
+      "V8CoverageConnection::End(), ending = %d\n", ending_);
+  if (ending_) {
+    return;
+  }
   ending_ = true;
-  DispatchMessage("Profiler.takePreciseCoverage");
+  TakeCoverage();
 }
 
 std::string V8CpuProfilerConnection::GetDirectory() const {
@@ -327,9 +344,14 @@
 }
 
 void V8CpuProfilerConnection::End() {
-  CHECK_EQ(ending_, false);
+  Debug(env_,
+      DebugCategory::INSPECTOR_PROFILER,
+      "V8CpuProfilerConnection::End(), ending = %d\n", ending_);
+  if (ending_) {
+    return;
+  }
   ending_ = true;
-  DispatchMessage("Profiler.stop");
+  DispatchMessage("Profiler.stop", nullptr, true);
 }
 
 std::string V8HeapProfilerConnection::GetDirectory() const {
@@ -365,31 +387,33 @@
 }
 
 void V8HeapProfilerConnection::End() {
-  CHECK_EQ(ending_, false);
+  Debug(env_,
+      DebugCategory::INSPECTOR_PROFILER,
+      "V8HeapProfilerConnection::End(), ending = %d\n", ending_);
+  if (ending_) {
+    return;
+  }
   ending_ = true;
-  DispatchMessage("HeapProfiler.stopSampling");
+  DispatchMessage("HeapProfiler.stopSampling", nullptr, true);
 }
 
 // For now, we only support coverage profiling, but we may add more
 // in the future.
 static void EndStartedProfilers(Environment* env) {
+  // TODO(joyeechueng): merge these connections and use one session per env.
   Debug(env, DebugCategory::INSPECTOR_PROFILER, "EndStartedProfilers\n");
   V8ProfilerConnection* connection = env->cpu_profiler_connection();
-  if (connection != nullptr && !connection->ending()) {
-    Debug(env, DebugCategory::INSPECTOR_PROFILER, "Ending cpu profiling\n");
+  if (connection != nullptr) {
     connection->End();
   }
 
   connection = env->heap_profiler_connection();
-  if (connection != nullptr && !connection->ending()) {
-    Debug(env, DebugCategory::INSPECTOR_PROFILER, "Ending heap profiling\n");
+  if (connection != nullptr) {
     connection->End();
   }
 
   connection = env->coverage_connection();
-  if (connection != nullptr && !connection->ending()) {
-    Debug(
-        env, DebugCategory::INSPECTOR_PROFILER, "Ending coverage collection\n");
+  if (connection != nullptr) {
     connection->End();
   }
 }
@@ -469,6 +493,37 @@
   env->set_source_map_cache_getter(args[0].As<Function>());
 }
 
+static void TakeCoverage(const FunctionCallbackInfo<Value>& args) {
+  Environment* env = Environment::GetCurrent(args);
+  V8CoverageConnection* connection = env->coverage_connection();
+
+  Debug(
+    env,
+    DebugCategory::INSPECTOR_PROFILER,
+    "TakeCoverage, connection %s nullptr\n",
+    connection == nullptr ? "==" : "!=");
+
+  if (connection != nullptr) {
+    Debug(env, DebugCategory::INSPECTOR_PROFILER, "taking coverage\n");
+    connection->TakeCoverage();
+  }
+}
+
+static void StopCoverage(const FunctionCallbackInfo<Value>& args) {
+  Environment* env = Environment::GetCurrent(args);
+  V8CoverageConnection* connection = env->coverage_connection();
+
+  Debug(env,
+        DebugCategory::INSPECTOR_PROFILER,
+        "StopCoverage, connection %s nullptr\n",
+        connection == nullptr ? "==" : "!=");
+
+  if (connection != nullptr) {
+    Debug(env, DebugCategory::INSPECTOR_PROFILER, "Stopping coverage\n");
+    connection->StopCoverage();
+  }
+}
+
 static void Initialize(Local<Object> target,
                        Local<Value> unused,
                        Local<Context> context,
@@ -476,6 +531,8 @@
   Environment* env = Environment::GetCurrent(context);
   env->SetMethod(target, "setCoverageDirectory", SetCoverageDirectory);
   env->SetMethod(target, "setSourceMapCacheGetter", SetSourceMapCacheGetter);
+  env->SetMethod(target, "takeCoverage", TakeCoverage);
+  env->SetMethod(target, "stopCoverage", StopCoverage);
 }
 
 }  // namespace profiler
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/inspector_profiler.h nodejs-12.22.4~dfsg/src/inspector_profiler.h
--- nodejs-12.21.0~dfsg/src/inspector_profiler.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/inspector_profiler.h	2021-07-29 12:35:25.000000000 +0200
@@ -7,6 +7,7 @@
 #error("This header can only be used when inspector is enabled")
 #endif
 
+#include <unordered_set>
 #include "inspector_agent.h"
 
 namespace node {
@@ -39,7 +40,9 @@
   // The optional `params` should be formatted in JSON.
   // The strings should be in one byte characters - which is enough for
   // the commands we use here.
-  size_t DispatchMessage(const char* method, const char* params = nullptr);
+  uint32_t DispatchMessage(const char* method,
+                           const char* params = nullptr,
+                           bool is_profile_request = false);
 
   // Use DispatchMessage() to dispatch necessary inspector messages
   // to start and end the profiling.
@@ -58,12 +61,19 @@
   // which will be then written as a JSON.
   virtual v8::MaybeLocal<v8::Object> GetProfile(
       v8::Local<v8::Object> result) = 0;
-  virtual void WriteProfile(v8::Local<v8::String> message);
+  virtual void WriteProfile(v8::Local<v8::Object> result);
+
+  bool HasProfileId(uint32_t id) const {
+    return profile_ids_.find(id) != profile_ids_.end();
+  }
+
+  void RemoveProfileId(uint32_t id) { profile_ids_.erase(id); }
 
  private:
-  size_t next_id() { return id_++; }
+  uint32_t next_id() { return id_++; }
   std::unique_ptr<inspector::InspectorSession> session_;
-  size_t id_ = 1;
+  uint32_t id_ = 1;
+  std::unordered_set<uint32_t> profile_ids_;
 
  protected:
   Environment* env_ = nullptr;
@@ -82,8 +92,10 @@
   std::string GetDirectory() const override;
   std::string GetFilename() const override;
   v8::MaybeLocal<v8::Object> GetProfile(v8::Local<v8::Object> result) override;
-  void WriteProfile(v8::Local<v8::String> message) override;
+  void WriteProfile(v8::Local<v8::Object> result) override;
   void WriteSourceMapCache();
+  void TakeCoverage();
+  void StopCoverage();
 
  private:
   std::unique_ptr<inspector::InspectorSession> session_;
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/js_native_api.h nodejs-12.22.4~dfsg/src/js_native_api.h
--- nodejs-12.21.0~dfsg/src/js_native_api.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/js_native_api.h	2021-07-29 12:35:25.000000000 +0200
@@ -17,7 +17,7 @@
 // functions available in a new version of N-API that is not yet ported in all
 // LTS versions, they can set NAPI_VERSION knowing that they have specifically
 // depended on that version.
-#define NAPI_VERSION 7
+#define NAPI_VERSION 8
 #endif
 #endif
 
@@ -539,7 +539,7 @@
                                                      bool* result);
 #endif  // NAPI_VERSION >= 7
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
 // Type tagging
 NAPI_EXTERN napi_status napi_type_tag_object(napi_env env,
                                              napi_value value,
@@ -554,7 +554,7 @@
                                            napi_value object);
 NAPI_EXTERN napi_status napi_object_seal(napi_env env,
                                          napi_value object);
-#endif  // NAPI_EXPERIMENTAL
+#endif  // NAPI_VERSION >= 8
 
 EXTERN_C_END
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/js_native_api_types.h nodejs-12.22.4~dfsg/src/js_native_api_types.h
--- nodejs-12.21.0~dfsg/src/js_native_api_types.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/js_native_api_types.h	2021-07-29 12:35:25.000000000 +0200
@@ -31,7 +31,7 @@
   // from instance properties. Ignored by napi_define_properties.
   napi_static = 1 << 10,
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
   // Default for class methods.
   napi_default_method = napi_writable | napi_configurable,
 
@@ -39,7 +39,7 @@
   napi_default_jsproperty = napi_writable |
                             napi_enumerable |
                             napi_configurable,
-#endif  // NAPI_EXPERIMENTAL
+#endif  // NAPI_VERSION >= 8
 } napi_property_attributes;
 
 typedef enum {
@@ -146,11 +146,11 @@
 } napi_key_conversion;
 #endif  // NAPI_VERSION >= 6
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
 typedef struct {
   uint64_t lower;
   uint64_t upper;
 } napi_type_tag;
-#endif  // NAPI_EXPERIMENTAL
+#endif  // NAPI_VERSION >= 8
 
 #endif  // SRC_JS_NATIVE_API_TYPES_H_
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_api.cc nodejs-12.22.4~dfsg/src/node_api.cc
--- nodejs-12.21.0~dfsg/src/node_api.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_api.cc	2021-07-29 12:35:25.000000000 +0200
@@ -12,8 +12,9 @@
 #include <memory>
 
 struct node_napi_env__ : public napi_env__ {
-  explicit node_napi_env__(v8::Local<v8::Context> context):
-      napi_env__(context) {
+  explicit node_napi_env__(v8::Local<v8::Context> context,
+                           const std::string& module_filename):
+      napi_env__(context), filename(module_filename) {
     CHECK_NOT_NULL(node_env());
   }
 
@@ -43,6 +44,10 @@
       });
     });
   }
+
+  const char* GetFilename() const { return filename.c_str(); }
+
+  std::string filename;
 };
 
 typedef node_napi_env__* node_napi_env;
@@ -84,10 +89,11 @@
   };
 };
 
-static inline napi_env NewEnv(v8::Local<v8::Context> context) {
+static inline napi_env
+NewEnv(v8::Local<v8::Context> context, const std::string& module_filename) {
   node_napi_env result;
 
-  result = new node_napi_env__(context);
+  result = new node_napi_env__(context, module_filename);
   // TODO(addaleax): There was previously code that tried to delete the
   // napi_env when its v8::Context was garbage collected;
   // However, as long as N-API addons using this napi_env are in place,
@@ -454,16 +460,35 @@
                                     v8::Local<v8::Value> module,
                                     v8::Local<v8::Context> context,
                                     napi_addon_register_func init) {
+  node::Environment* node_env = node::Environment::GetCurrent(context);
+  std::string module_filename = "";
   if (init == nullptr) {
-    node::Environment* node_env = node::Environment::GetCurrent(context);
     CHECK_NOT_NULL(node_env);
     node_env->ThrowError(
         "Module has no declared entry point.");
     return;
   }
 
+  // We set `env->filename` from `module.filename` here, but we could just as
+  // easily add a private property to `exports` in `process.dlopen`, which
+  // receives the file name from JS, and retrieve *that* here. Thus, we are not
+  // endorsing commonjs here by making use of `module.filename`.
+  v8::Local<v8::Value> filename_js;
+  v8::Local<v8::Object> modobj;
+  if (module->ToObject(context).ToLocal(&modobj) &&
+      modobj->Get(context, node_env->filename_string()).ToLocal(&filename_js) &&
+      filename_js->IsString()) {
+    node::Utf8Value filename(node_env->isolate(), filename_js);  // Cast
+
+    // Turn the absolute path into a URL. Currently the absolute path is always
+    // a file system path.
+    // TODO(gabrielschulhof): Pass the `filename` through unchanged if/when we
+    // receive it as a URL already.
+    module_filename = std::string("file://") + (*filename);
+  }
+
   // Create a new napi_env for this specific module.
-  napi_env env = v8impl::NewEnv(context);
+  napi_env env = v8impl::NewEnv(context, module_filename);
 
   napi_value _exports;
   env->CallIntoModule([&](napi_env env) {
@@ -1154,3 +1179,11 @@
   CHECK_NOT_NULL(func);
   return reinterpret_cast<v8impl::ThreadSafeFunction*>(func)->Ref();
 }
+
+napi_status node_api_get_module_file_name(napi_env env, const char** result) {
+  CHECK_ENV(env);
+  CHECK_ARG(env, result);
+
+  *result = static_cast<node_napi_env>(env)->GetFilename();
+  return napi_clear_last_error(env);
+}
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_api.h nodejs-12.22.4~dfsg/src/node_api.h
--- nodejs-12.21.0~dfsg/src/node_api.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_api.h	2021-07-29 12:35:25.000000000 +0200
@@ -250,7 +250,7 @@
 
 #endif  // NAPI_VERSION >= 4
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
 
 NAPI_EXTERN napi_status napi_add_async_cleanup_hook(
     napi_env env,
@@ -261,6 +261,13 @@
 NAPI_EXTERN napi_status napi_remove_async_cleanup_hook(
     napi_async_cleanup_hook_handle remove_handle);
 
+#endif  // NAPI_VERSION >= 8
+
+#ifdef NAPI_EXPERIMENTAL
+
+NAPI_EXTERN napi_status
+node_api_get_module_file_name(napi_env env, const char** result);
+
 #endif  // NAPI_EXPERIMENTAL
 
 EXTERN_C_END
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_api_types.h nodejs-12.22.4~dfsg/src/node_api_types.h
--- nodejs-12.21.0~dfsg/src/node_api_types.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_api_types.h	2021-07-29 12:35:25.000000000 +0200
@@ -41,10 +41,10 @@
   const char* release;
 } napi_node_version;
 
-#ifdef NAPI_EXPERIMENTAL
+#if NAPI_VERSION >= 8
 typedef struct napi_async_cleanup_hook_handle__* napi_async_cleanup_hook_handle;
 typedef void (*napi_async_cleanup_hook)(napi_async_cleanup_hook_handle handle,
                                         void* data);
-#endif  // NAPI_EXPERIMENTAL
+#endif  // NAPI_VERSION >= 8
 
 #endif  // SRC_NODE_API_TYPES_H_
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node.cc nodejs-12.22.4~dfsg/src/node.cc
--- nodejs-12.21.0~dfsg/src/node.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node.cc	2021-07-29 12:35:25.000000000 +0200
@@ -1035,7 +1035,7 @@
 }
 
 int Stop(Environment* env) {
-  env->Stop();
+  env->ExitEnv();
   return 0;
 }
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node.h nodejs-12.22.4~dfsg/src/node.h
--- nodejs-12.21.0~dfsg/src/node.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node.h	2021-07-29 12:35:25.000000000 +0200
@@ -218,8 +218,7 @@
 NODE_EXTERN int Start(int argc, char* argv[]);
 
 // Tear down Node.js while it is running (there are active handles
-// in the loop and / or actively executing JavaScript code). This also stops
-// all Workers that may have been started earlier.
+// in the loop and / or actively executing JavaScript code).
 NODE_EXTERN int Stop(Environment* env);
 
 // TODO(addaleax): Officially deprecate this and replace it with something
@@ -469,8 +468,8 @@
 // It receives the Environment* instance and the exit code as arguments.
 // This could e.g. call Stop(env); in order to terminate execution and stop
 // the event loop.
-// The default handler calls Stop(), disposes of the global V8 platform
-// instance, if one is being used, and calls exit().
+// The default handler disposes of the global V8 platform instance, if one is
+// being used, and calls exit().
 NODE_EXTERN void SetProcessExitHandler(
     Environment* env,
     std::function<void(Environment*, int)>&& handler);
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_http2.cc nodejs-12.22.4~dfsg/src/node_http2.cc
--- nodejs-12.21.0~dfsg/src/node_http2.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_http2.cc	2021-07-29 12:35:25.000000000 +0200
@@ -2150,6 +2150,23 @@
 void Http2Stream::SubmitRstStream(const uint32_t code) {
   CHECK(!this->IsDestroyed());
   code_ = code;
+
+  // If RST_STREAM frame is received and stream is not writable
+  // because it is busy reading data, don't try force purging it.
+  // Instead add the stream to pending stream list and process
+  // the pending data when it is safe to do so. This is to avoid
+  // double free error due to unwanted behavior of nghttp2.
+  // Ref:https://github.com/nodejs/node/issues/38964
+
+  // Add stream to the pending list if it is received with scope
+  // below in the stack. The pending list may not get processed
+  // if RST_STREAM received is not in scope and added to the list
+  // causing endpoint to hang.
+  if (session_->is_in_scope() && IsReading()) {
+      session_->AddPendingRstStream(id_);
+      return;
+  }
+
   // If possible, force a purge of any currently pending data here to make sure
   // it is sent before closing the stream. If it returns non-zero then we need
   // to wait until the current write finishes and try again to avoid nghttp2
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_http2.h nodejs-12.22.4~dfsg/src/node_http2.h
--- nodejs-12.21.0~dfsg/src/node_http2.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_http2.h	2021-07-29 12:35:25.000000000 +0200
@@ -764,6 +764,22 @@
     return (flags_ & SESSION_STATE_CLOSED) || session_ == nullptr;
   }
 
+
+  // The changes are backported and exposes APIs to check the
+  // status flag of `Http2Session`
+#define IS_FLAG(name, flag)                                                    \
+  bool is_##name() const { return flags_ & flag; }
+
+  IS_FLAG(in_scope, SESSION_STATE_HAS_SCOPE)
+  IS_FLAG(write_scheduled, SESSION_STATE_WRITE_SCHEDULED)
+  IS_FLAG(closing, SESSION_STATE_CLOSING)
+  IS_FLAG(sending, SESSION_STATE_SENDING)
+  IS_FLAG(write_in_progress, SESSION_STATE_WRITE_IN_PROGRESS)
+  IS_FLAG(reading_stopped, SESSION_STATE_READING_STOPPED)
+  IS_FLAG(receive_paused, SESSION_STATE_NGHTTP2_RECV_PAUSED)
+
+#undef IS_FLAG
+
   // Schedule a write if nghttp2 indicates it wants to write to the socket.
   void MaybeScheduleWrite();
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_http_parser_impl.h nodejs-12.22.4~dfsg/src/node_http_parser_impl.h
--- nodejs-12.21.0~dfsg/src/node_http_parser_impl.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_http_parser_impl.h	2021-07-29 12:35:25.000000000 +0200
@@ -26,6 +26,9 @@
 
 #include "node.h"
 #include "node_buffer.h"
+#ifndef NODE_EXPERIMENTAL_HTTP
+#include "node_process.h"
+#endif  /* NODE_EXPERIMENTAL_HTTP */
 #include "util.h"
 
 #include "async_wrap-inl.h"
@@ -1021,6 +1024,10 @@
 #ifndef NODE_EXPERIMENTAL_HTTP
   static uv_once_t init_once = UV_ONCE_INIT;
   uv_once(&init_once, InitMaxHttpHeaderSizeOnce);
+  ProcessEmitDeprecationWarning(
+    env,
+    "The legacy HTTP parser is deprecated.",
+    "DEP0131").IsNothing();
 #endif  /* NODE_EXPERIMENTAL_HTTP */
 }
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_platform.cc nodejs-12.22.4~dfsg/src/node_platform.cc
--- nodejs-12.21.0~dfsg/src/node_platform.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_platform.cc	2021-07-29 12:35:25.000000000 +0200
@@ -359,10 +359,10 @@
   Mutex::ScopedLock lock(per_isolate_mutex_);
   auto it = per_isolate_.find(isolate);
   if (it == per_isolate_.end()) {
-    CHECK(it->second);
     cb(data);
     return;
   }
+  CHECK(it->second);
   it->second->AddShutdownCallback(cb, data);
 }
 
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_version.h nodejs-12.22.4~dfsg/src/node_version.h
--- nodejs-12.21.0~dfsg/src/node_version.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_version.h	2021-07-29 12:35:25.000000000 +0200
@@ -23,8 +23,8 @@
 #define SRC_NODE_VERSION_H_
 
 #define NODE_MAJOR_VERSION 12
-#define NODE_MINOR_VERSION 21
-#define NODE_PATCH_VERSION 0
+#define NODE_MINOR_VERSION 22
+#define NODE_PATCH_VERSION 4
 
 #define NODE_VERSION_IS_LTS 1
 #define NODE_VERSION_LTS_CODENAME "Erbium"
@@ -93,6 +93,6 @@
 
 // The NAPI_VERSION provided by this version of the runtime. This is the version
 // which the Node binary being built supports.
-#define NAPI_VERSION  7
+#define NAPI_VERSION  8
 
 #endif  // SRC_NODE_VERSION_H_
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_worker.cc nodejs-12.22.4~dfsg/src/node_worker.cc
--- nodejs-12.21.0~dfsg/src/node_worker.cc	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_worker.cc	2021-07-29 12:35:25.000000000 +0200
@@ -765,6 +765,39 @@
   args.GetReturnValue().Set(scheduled ? taker->object() : Local<Object>());
 }
 
+void Worker::LoopIdleTime(const FunctionCallbackInfo<Value>& args) {
+  Worker* w;
+  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
+
+  Mutex::ScopedLock lock(w->mutex_);
+  // Using w->is_stopped() here leads to a deadlock, and checking is_stopped()
+  // before locking the mutex is a race condition. So manually do the same
+  // check.
+  if (w->stopped_ || w->env_ == nullptr)
+    return args.GetReturnValue().Set(-1);
+
+  uint64_t idle_time = uv_metrics_idle_time(w->env_->event_loop());
+  args.GetReturnValue().Set(1.0 * idle_time / 1e6);
+}
+
+void Worker::LoopStartTime(const FunctionCallbackInfo<Value>& args) {
+  Worker* w;
+  ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
+
+  Mutex::ScopedLock lock(w->mutex_);
+  // Using w->is_stopped() here leads to a deadlock, and checking is_stopped()
+  // before locking the mutex is a race condition. So manually do the same
+  // check.
+  if (w->stopped_ || w->env_ == nullptr)
+    return args.GetReturnValue().Set(-1);
+
+  double loop_start_time = w->env_->performance_state()->milestones[
+      node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START];
+  CHECK_GE(loop_start_time, 0);
+  args.GetReturnValue().Set(
+      (loop_start_time - node::performance::timeOrigin) / 1e6);
+}
+
 namespace {
 
 // Return the MessagePort that is global for this Environment and communicates
@@ -798,6 +831,8 @@
     env->SetProtoMethod(w, "unref", Worker::Unref);
     env->SetProtoMethod(w, "getResourceLimits", Worker::GetResourceLimits);
     env->SetProtoMethod(w, "takeHeapSnapshot", Worker::TakeHeapSnapshot);
+    env->SetProtoMethod(w, "loopIdleTime", Worker::LoopIdleTime);
+    env->SetProtoMethod(w, "loopStartTime", Worker::LoopStartTime);
 
     Local<String> workerString =
         FIXED_ONE_BYTE_STRING(env->isolate(), "Worker");
diff -Nru --exclude '*.md' --exclude '*.html' --exclude '*.json' --exclude '*.ts' nodejs-12.21.0~dfsg/src/node_worker.h nodejs-12.22.4~dfsg/src/node_worker.h
--- nodejs-12.21.0~dfsg/src/node_worker.h	2021-02-23 03:58:07.000000000 +0100
+++ nodejs-12.22.4~dfsg/src/node_worker.h	2021-07-29 12:35:25.000000000 +0200
@@ -66,6 +66,8 @@
       const v8::FunctionCallbackInfo<v8::Value>& args);
   v8::Local<v8::Float64Array> GetResourceLimits(v8::Isolate* isolate) const;
   static void TakeHeapSnapshot(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void LoopIdleTime(const v8::FunctionCallbackInfo<v8::Value>& args);
+  static void LoopStartTime(const v8::FunctionCallbackInfo<v8::Value>& args);
 
  private:
   void CreateEnvMessagePort(Environment* env);

 

--- End Message ---
--- Begin Message ---
I just double-checked nodejs 12.22.4 was actually fixing
CVE-2021-22930, supposed to be reproducible with
https://github.com/mdouglass/repro-node-crash

It does not, so i'm closing this bug until i find out what's happening.

Jérémy

--- End Message ---

Reply to: