Skip to content

Commit 728f512

Browse files
aduh95targos
authored andcommitted
lib: make safe primordials safe to iterate
PR-URL: #36391 Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 9f2d3c2 commit 728f512

File tree

4 files changed

+55
-18
lines changed

4 files changed

+55
-18
lines changed

lib/internal/per_context/primordials.js

+44-1
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,52 @@ function copyPrototype(src, dest, prefix) {
9191
}
9292
}
9393

94+
const createSafeIterator = (factory, next) => {
95+
class SafeIterator {
96+
constructor(iterable) {
97+
this._iterator = factory(iterable);
98+
}
99+
next() {
100+
return next(this._iterator);
101+
}
102+
[Symbol.iterator]() {
103+
return this;
104+
}
105+
}
106+
Object.setPrototypeOf(SafeIterator.prototype, null);
107+
Object.freeze(SafeIterator.prototype);
108+
Object.freeze(SafeIterator);
109+
return SafeIterator;
110+
};
111+
94112
function makeSafe(unsafe, safe) {
95-
copyProps(unsafe.prototype, safe.prototype);
113+
if (Symbol.iterator in unsafe.prototype) {
114+
const dummy = new unsafe();
115+
let next; // We can reuse the same `next` method.
116+
117+
for (const key of Reflect.ownKeys(unsafe.prototype)) {
118+
if (!Reflect.getOwnPropertyDescriptor(safe.prototype, key)) {
119+
const desc = Reflect.getOwnPropertyDescriptor(unsafe.prototype, key);
120+
if (
121+
typeof desc.value === 'function' &&
122+
desc.value.length === 0 &&
123+
Symbol.iterator in (desc.value.call(dummy) ?? {})
124+
) {
125+
const createIterator = uncurryThis(desc.value);
126+
next ??= uncurryThis(createIterator(dummy).next);
127+
const SafeIterator = createSafeIterator(createIterator, next);
128+
desc.value = function() {
129+
return new SafeIterator(this);
130+
};
131+
}
132+
Reflect.defineProperty(safe.prototype, key, desc);
133+
}
134+
}
135+
} else {
136+
copyProps(unsafe.prototype, safe.prototype);
137+
}
96138
copyProps(unsafe, safe);
139+
97140
Object.setPrototypeOf(safe.prototype, null);
98141
Object.freeze(safe.prototype);
99142
Object.freeze(safe);

lib/internal/source_map/source_map_cache.js

+1-10
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,12 @@ const {
77
ObjectKeys,
88
ObjectGetOwnPropertyDescriptor,
99
ObjectPrototypeHasOwnProperty,
10-
Map,
11-
MapPrototypeEntries,
1210
RegExpPrototypeTest,
1311
SafeMap,
1412
StringPrototypeMatch,
1513
StringPrototypeSplit,
16-
uncurryThis,
1714
} = primordials;
1815

19-
const MapIteratorNext = uncurryThis(MapPrototypeEntries(new Map()).next);
20-
2116
function ObjectGetValueSafe(obj, key) {
2217
const desc = ObjectGetOwnPropertyDescriptor(obj, key);
2318
return ObjectPrototypeHasOwnProperty(desc, 'value') ? desc.value : undefined;
@@ -195,11 +190,7 @@ function rekeySourceMap(cjsModuleInstance, newInstance) {
195190
function sourceMapCacheToObject() {
196191
const obj = ObjectCreate(null);
197192

198-
const it = MapPrototypeEntries(esmSourceMapCache);
199-
let entry;
200-
while (!(entry = MapIteratorNext(it)).done) {
201-
const k = entry.value[0];
202-
const v = entry.value[1];
193+
for (const { 0: k, 1: v } of esmSourceMapCache) {
203194
obj[k] = v;
204195
}
205196

lib/internal/worker/io.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const {
4+
ArrayPrototypeForEach,
45
ArrayPrototypeMap,
56
ArrayPrototypePush,
67
FunctionPrototypeBind,
@@ -315,8 +316,7 @@ class WritableWorkerStdio extends Writable {
315316
[kStdioWantsMoreDataCallback]() {
316317
const cbs = this[kWritableCallbacks];
317318
this[kWritableCallbacks] = [];
318-
for (const cb of cbs)
319-
cb();
319+
ArrayPrototypeForEach(cbs, (cb) => cb());
320320
if ((this[kPort][kWaitingStreams] -= cbs.length) === 0)
321321
this[kPort].unref();
322322
}

test/parallel/test-worker-terminate-source-map.js

+8-5
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,19 @@ const { callCount } = workerData;
2727
function increaseCallCount() { callCount[0]++; }
2828

2929
// Increase the call count when a forbidden method is called.
30-
Object.getPrototypeOf((new Map()).entries()).next = increaseCallCount;
31-
Map.prototype.entries = increaseCallCount;
32-
Object.keys = increaseCallCount;
33-
Object.create = increaseCallCount;
34-
Object.hasOwnProperty = increaseCallCount;
3530
for (const property of ['_cache', 'lineLengths', 'url']) {
3631
Object.defineProperty(Object.prototype, property, {
3732
get: increaseCallCount,
3833
set: increaseCallCount
3934
});
4035
}
36+
Object.getPrototypeOf([][Symbol.iterator]()).next = increaseCallCount;
37+
Object.getPrototypeOf((new Map()).entries()).next = increaseCallCount;
38+
Array.prototype[Symbol.iterator] = increaseCallCount;
39+
Map.prototype[Symbol.iterator] = increaseCallCount;
40+
Map.prototype.entries = increaseCallCount;
41+
Object.keys = increaseCallCount;
42+
Object.create = increaseCallCount;
43+
Object.hasOwnProperty = increaseCallCount;
4144

4245
parentPort.postMessage('done');

0 commit comments

Comments
 (0)