From 6e218f950983673c1d119cd3d97d4af4bb0d236b Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Fri, 4 Dec 2020 12:35:49 +0100 Subject: [PATCH 01/11] lib: make safe primordials safe to iterate --- lib/internal/modules/cjs/loader.js | 2 +- lib/internal/per_context/primordials.js | 11 +++++++++++ lib/internal/source_map/source_map_cache.js | 11 +---------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 037d872e1d4fa1..81ff1c8078116c 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -1269,7 +1269,7 @@ Module._preloadModules = function(requests) { }; Module.syncBuiltinESMExports = function syncBuiltinESMExports() { - for (const mod of NativeModule.map.values()) { + for (const [, mod] of NativeModule.map) { if (mod.canBeRequiredByUsers) { mod.syncExports(); } diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index baaca6d273f86c..10ed118c0dbcf2 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -75,6 +75,17 @@ function copyPrototype(src, dest, prefix) { function makeSafe(unsafe, safe) { copyProps(unsafe.prototype, safe.prototype); copyProps(unsafe, safe); + if (Symbol.iterator in unsafe.prototype) { + const createIterator = uncurryThis(unsafe.prototype[Symbol.iterator]); + const next = uncurryThis( + Reflect.getPrototypeOf(createIterator(new unsafe())).next + ); + safe.prototype[Symbol.iterator] = function*() { + const iterator = createIterator(this); + let entry; + while (!(entry = next(iterator)).done) yield entry.value; + }; + } Object.setPrototypeOf(safe.prototype, null); Object.freeze(safe.prototype); Object.freeze(safe); diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index ff259ee4325d1d..4fd16382288547 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -7,17 +7,12 @@ const { ObjectKeys, ObjectGetOwnPropertyDescriptor, ObjectPrototypeHasOwnProperty, - Map, - MapPrototypeEntries, RegExpPrototypeTest, SafeMap, StringPrototypeMatch, StringPrototypeSplit, - uncurryThis, } = primordials; -const MapIteratorNext = uncurryThis(MapPrototypeEntries(new Map()).next); - function ObjectGetValueSafe(obj, key) { const desc = ObjectGetOwnPropertyDescriptor(obj, key); return ObjectPrototypeHasOwnProperty(desc, 'value') ? desc.value : undefined; @@ -195,11 +190,7 @@ function rekeySourceMap(cjsModuleInstance, newInstance) { function sourceMapCacheToObject() { const obj = ObjectCreate(null); - const it = MapPrototypeEntries(esmSourceMapCache); - let entry; - while (!(entry = MapIteratorNext(it)).done) { - const k = entry.value[0]; - const v = entry.value[1]; + for (const [k, v] of esmSourceMapCache) { obj[k] = v; } From cc40d414917d3f7ffba3e766b42f551c6c9d71e5 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 5 Dec 2020 12:56:59 +0100 Subject: [PATCH 02/11] fixup! lib: make safe primordials safe to iterate --- lib/inspector.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/inspector.js b/lib/inspector.js index 60640bc1fb6456..29012e23f0629c 100644 --- a/lib/inspector.js +++ b/lib/inspector.js @@ -123,8 +123,7 @@ class Session extends EventEmitter { return; this[connectionSymbol].disconnect(); this[connectionSymbol] = null; - const remainingCallbacks = this[messageCallbacksSymbol].values(); - for (const callback of remainingCallbacks) { + for (const [, callback] of this[messageCallbacksSymbol]) { process.nextTick(callback, new ERR_INSPECTOR_CLOSED()); } this[messageCallbacksSymbol].clear(); From 0e6ecc07e028630d30e34fd1cc9469b19bac9670 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 6 Dec 2020 12:19:14 +0100 Subject: [PATCH 03/11] fixup! lib: make safe primordials safe to iterate --- lib/internal/per_context/primordials.js | 27 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index 10ed118c0dbcf2..75b19935d3b503 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -72,19 +72,30 @@ function copyPrototype(src, dest, prefix) { } } +const createSafeIterator = (factory, next) => { + class SafeIterator { + constructor(iterable) { + this._iterator = factory(iterable); + } + next() { + return next(this._iterator); + } + } + Object.setPrototypeOf(SafeIterator.prototype, null); + Object.freeze(SafeIterator.prototype); + Object.freeze(SafeIterator); + return function () { + return new SafeIterator(this); + }; +}; + function makeSafe(unsafe, safe) { copyProps(unsafe.prototype, safe.prototype); copyProps(unsafe, safe); if (Symbol.iterator in unsafe.prototype) { const createIterator = uncurryThis(unsafe.prototype[Symbol.iterator]); - const next = uncurryThis( - Reflect.getPrototypeOf(createIterator(new unsafe())).next - ); - safe.prototype[Symbol.iterator] = function*() { - const iterator = createIterator(this); - let entry; - while (!(entry = next(iterator)).done) yield entry.value; - }; + const next = uncurryThis(createIterator(new unsafe()).next); + safe.prototype[Symbol.iterator] = createSafeIterator(createIterator, next); } Object.setPrototypeOf(safe.prototype, null); Object.freeze(safe.prototype); From 6a4e2abbaf0d255ec357f9566d2001c7ca3db8b7 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 6 Dec 2020 12:22:52 +0100 Subject: [PATCH 04/11] fixup! lib: make safe primordials safe to iterate --- lib/internal/per_context/primordials.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index 75b19935d3b503..e66343b47cbb9d 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -84,7 +84,7 @@ const createSafeIterator = (factory, next) => { Object.setPrototypeOf(SafeIterator.prototype, null); Object.freeze(SafeIterator.prototype); Object.freeze(SafeIterator); - return function () { + return function() { return new SafeIterator(this); }; }; From cf5374855af25ca9da5e8446f40f949ebb7e0826 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 7 Dec 2020 15:08:08 +0100 Subject: [PATCH 05/11] fixup! lib: make safe primordials safe to iterate --- lib/internal/per_context/primordials.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index e66343b47cbb9d..82809edced84a1 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -84,9 +84,7 @@ const createSafeIterator = (factory, next) => { Object.setPrototypeOf(SafeIterator.prototype, null); Object.freeze(SafeIterator.prototype); Object.freeze(SafeIterator); - return function() { - return new SafeIterator(this); - }; + return SafeIterator; }; function makeSafe(unsafe, safe) { @@ -95,7 +93,10 @@ function makeSafe(unsafe, safe) { if (Symbol.iterator in unsafe.prototype) { const createIterator = uncurryThis(unsafe.prototype[Symbol.iterator]); const next = uncurryThis(createIterator(new unsafe()).next); - safe.prototype[Symbol.iterator] = createSafeIterator(createIterator, next); + const SafeIterator = createSafeIterator(createIterator, next); + safe.prototype[Symbol.iterator] = function() { + return new SafeIterator(this); + }; } Object.setPrototypeOf(safe.prototype, null); Object.freeze(safe.prototype); From 3939f68deef96d3bdb31f6f5da17c19e04384a0f Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 8 Dec 2020 19:13:16 +0100 Subject: [PATCH 06/11] fixup! lib: make safe primordials safe to iterate --- lib/inspector.js | 3 +- lib/internal/modules/cjs/loader.js | 2 +- lib/internal/per_context/primordials.js | 36 ++++++++++++++++----- lib/internal/source_map/source_map_cache.js | 4 ++- 4 files changed, 34 insertions(+), 11 deletions(-) diff --git a/lib/inspector.js b/lib/inspector.js index 29012e23f0629c..60640bc1fb6456 100644 --- a/lib/inspector.js +++ b/lib/inspector.js @@ -123,7 +123,8 @@ class Session extends EventEmitter { return; this[connectionSymbol].disconnect(); this[connectionSymbol] = null; - for (const [, callback] of this[messageCallbacksSymbol]) { + const remainingCallbacks = this[messageCallbacksSymbol].values(); + for (const callback of remainingCallbacks) { process.nextTick(callback, new ERR_INSPECTOR_CLOSED()); } this[messageCallbacksSymbol].clear(); diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index 81ff1c8078116c..037d872e1d4fa1 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -1269,7 +1269,7 @@ Module._preloadModules = function(requests) { }; Module.syncBuiltinESMExports = function syncBuiltinESMExports() { - for (const [, mod] of NativeModule.map) { + for (const mod of NativeModule.map.values()) { if (mod.canBeRequiredByUsers) { mod.syncExports(); } diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index 82809edced84a1..a82b43ffca1e95 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -80,6 +80,9 @@ const createSafeIterator = (factory, next) => { next() { return next(this._iterator); } + [Symbol.iterator]() { + return this; + } } Object.setPrototypeOf(SafeIterator.prototype, null); Object.freeze(SafeIterator.prototype); @@ -88,16 +91,33 @@ const createSafeIterator = (factory, next) => { }; function makeSafe(unsafe, safe) { - copyProps(unsafe.prototype, safe.prototype); - copyProps(unsafe, safe); if (Symbol.iterator in unsafe.prototype) { - const createIterator = uncurryThis(unsafe.prototype[Symbol.iterator]); - const next = uncurryThis(createIterator(new unsafe()).next); - const SafeIterator = createSafeIterator(createIterator, next); - safe.prototype[Symbol.iterator] = function() { - return new SafeIterator(this); - }; + const dummy = new unsafe(); + let next; // We can reuse the same `next` method. + + for (const key of Reflect.ownKeys(unsafe.prototype)) { + if (!Reflect.getOwnPropertyDescriptor(safe.prototype, key)) { + const desc = Reflect.getOwnPropertyDescriptor(unsafe.prototype, key); + if ( + typeof desc.value === 'function' && + desc.value.length === 0 && + Symbol.iterator in (desc.value.call(dummy) ?? {}) + ) { + const createIterator = uncurryThis(desc.value); + next ??= uncurryThis(createIterator(dummy).next); + const SafeIterator = createSafeIterator(createIterator, next); + desc.value = function() { + return new SafeIterator(this); + }; + } + Reflect.defineProperty(safe.prototype, key, desc); + } + } + } else { + copyProps(unsafe.prototype, safe.prototype); } + copyProps(unsafe, safe); + Object.setPrototypeOf(safe.prototype, null); Object.freeze(safe.prototype); Object.freeze(safe); diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index 4fd16382288547..6ef2736e0f0be2 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -190,7 +190,9 @@ function rekeySourceMap(cjsModuleInstance, newInstance) { function sourceMapCacheToObject() { const obj = ObjectCreate(null); - for (const [k, v] of esmSourceMapCache) { + for (const entry of esmSourceMapCache) { + const k = entry[0]; + const v = entry[1]; obj[k] = v; } From 28a221894c6fca28630a6d712a79ccfcd7d3e467 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Fri, 11 Dec 2020 15:20:02 +0100 Subject: [PATCH 07/11] fixup! lib: make safe primordials safe to iterate --- test/parallel/test-worker-terminate-source-map.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/parallel/test-worker-terminate-source-map.js b/test/parallel/test-worker-terminate-source-map.js index 8cd40a6607422c..1c477266f59485 100644 --- a/test/parallel/test-worker-terminate-source-map.js +++ b/test/parallel/test-worker-terminate-source-map.js @@ -27,7 +27,10 @@ const { callCount } = workerData; function increaseCallCount() { callCount[0]++; } // Increase the call count when a forbidden method is called. +Object.getPrototypeOf([][Symbol.iterator]()).next = increaseCallCount; Object.getPrototypeOf((new Map()).entries()).next = increaseCallCount; +Array.prototype[Symbol.iterator] = increaseCallCount; +Map.prototype[Symbol.iterator] = increaseCallCount; Map.prototype.entries = increaseCallCount; Object.keys = increaseCallCount; Object.create = increaseCallCount; From 4b87c3b4b9f882131a77a64a9b4d7aa82ef08117 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Fri, 11 Dec 2020 16:14:45 +0100 Subject: [PATCH 08/11] fixup! lib: make safe primordials safe to iterate --- test/parallel/test-worker-terminate-source-map.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/parallel/test-worker-terminate-source-map.js b/test/parallel/test-worker-terminate-source-map.js index 1c477266f59485..c855dab975be01 100644 --- a/test/parallel/test-worker-terminate-source-map.js +++ b/test/parallel/test-worker-terminate-source-map.js @@ -27,6 +27,12 @@ const { callCount } = workerData; function increaseCallCount() { callCount[0]++; } // Increase the call count when a forbidden method is called. +for (const property of ['_cache', 'lineLengths', 'url']) { + Object.defineProperty(Object.prototype, property, { + get: increaseCallCount, + set: increaseCallCount + }); +} Object.getPrototypeOf([][Symbol.iterator]()).next = increaseCallCount; Object.getPrototypeOf((new Map()).entries()).next = increaseCallCount; Array.prototype[Symbol.iterator] = increaseCallCount; @@ -35,11 +41,5 @@ Map.prototype.entries = increaseCallCount; Object.keys = increaseCallCount; Object.create = increaseCallCount; Object.hasOwnProperty = increaseCallCount; -for (const property of ['_cache', 'lineLengths', 'url']) { - Object.defineProperty(Object.prototype, property, { - get: increaseCallCount, - set: increaseCallCount - }); -} parentPort.postMessage('done'); From 036ff05bfeefbb1ba02b9aefd35c0964260104d5 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 12 Dec 2020 15:27:41 +0100 Subject: [PATCH 09/11] fixup! lib: make safe primordials safe to iterate --- lib/internal/worker/io.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/internal/worker/io.js b/lib/internal/worker/io.js index 5bec78e81fa6df..42f00a2cfb9553 100644 --- a/lib/internal/worker/io.js +++ b/lib/internal/worker/io.js @@ -1,6 +1,7 @@ 'use strict'; const { + ArrayPrototypeForEach, ArrayPrototypeMap, ArrayPrototypePush, FunctionPrototypeCall, @@ -314,8 +315,7 @@ class WritableWorkerStdio extends Writable { [kStdioWantsMoreDataCallback]() { const cbs = this[kWritableCallbacks]; this[kWritableCallbacks] = []; - for (const cb of cbs) - cb(); + ArrayPrototypeForEach(cbs, FunctionPrototypeCall); if ((this[kPort][kWaitingStreams] -= cbs.length) === 0) this[kPort].unref(); } From c90d0ca821300feb0f36bfc9f85225b19223b124 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 12 Dec 2020 16:59:30 +0100 Subject: [PATCH 10/11] fixup! lib: make safe primordials safe to iterate --- lib/internal/worker/io.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/worker/io.js b/lib/internal/worker/io.js index 42f00a2cfb9553..5fdcb129ada19a 100644 --- a/lib/internal/worker/io.js +++ b/lib/internal/worker/io.js @@ -315,7 +315,7 @@ class WritableWorkerStdio extends Writable { [kStdioWantsMoreDataCallback]() { const cbs = this[kWritableCallbacks]; this[kWritableCallbacks] = []; - ArrayPrototypeForEach(cbs, FunctionPrototypeCall); + ArrayPrototypeForEach(cbs, (cb) => cb()); if ((this[kPort][kWaitingStreams] -= cbs.length) === 0) this[kPort].unref(); } From 1691a889d04396267801b706e1396a0b1e503bba Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 12 Dec 2020 12:41:37 -0500 Subject: [PATCH 11/11] fixup! lib: make safe primordials safe to iterate Co-authored-by: ExE Boss <3889017+ExE-Boss@users.noreply.github.com> --- lib/internal/source_map/source_map_cache.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/internal/source_map/source_map_cache.js b/lib/internal/source_map/source_map_cache.js index 6ef2736e0f0be2..b95653ebba84e9 100644 --- a/lib/internal/source_map/source_map_cache.js +++ b/lib/internal/source_map/source_map_cache.js @@ -190,9 +190,7 @@ function rekeySourceMap(cjsModuleInstance, newInstance) { function sourceMapCacheToObject() { const obj = ObjectCreate(null); - for (const entry of esmSourceMapCache) { - const k = entry[0]; - const v = entry[1]; + for (const { 0: k, 1: v } of esmSourceMapCache) { obj[k] = v; }