Skip to content

Commit

Permalink
lib: make safe primordials safe to iterate
Browse files Browse the repository at this point in the history
PR-URL: #36391
Backport-PR-URL: #38703
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
aduh95 authored and targos committed Jun 5, 2021
1 parent 4e99edb commit a07bc82
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 18 deletions.
45 changes: 44 additions & 1 deletion lib/internal/per_context/primordials.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,52 @@ function copyPrototype(src, dest, prefix) {
}
}

const createSafeIterator = (factory, next) => {
class SafeIterator {
constructor(iterable) {
this._iterator = factory(iterable);
}
next() {
return next(this._iterator);
}
[Symbol.iterator]() {
return this;
}
}
Object.setPrototypeOf(SafeIterator.prototype, null);
Object.freeze(SafeIterator.prototype);
Object.freeze(SafeIterator);
return SafeIterator;
};

function makeSafe(unsafe, safe) {
copyProps(unsafe.prototype, safe.prototype);
if (Symbol.iterator in unsafe.prototype) {
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);
if (next == null) 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);
Expand Down
11 changes: 1 addition & 10 deletions lib/internal/source_map/source_map_cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 { 0: k, 1: v } of esmSourceMapCache) {
obj[k] = v;
}

Expand Down
4 changes: 2 additions & 2 deletions lib/internal/worker/io.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const {
ArrayPrototypeForEach,
ArrayPrototypeMap,
ArrayPrototypePush,
FunctionPrototypeCall,
Expand Down Expand Up @@ -259,8 +260,7 @@ class WritableWorkerStdio extends Writable {
[kStdioWantsMoreDataCallback]() {
const cbs = this[kWritableCallbacks];
this[kWritableCallbacks] = [];
for (const cb of cbs)
cb();
ArrayPrototypeForEach(cbs, (cb) => cb());
if ((this[kPort][kWaitingStreams] -= cbs.length) === 0)
this[kPort].unref();
}
Expand Down
13 changes: 8 additions & 5 deletions test/parallel/test-worker-terminate-source-map.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,19 @@ const { callCount } = workerData;
function increaseCallCount() { callCount[0]++; }

// Increase the call count when a forbidden method is called.
Object.getPrototypeOf((new Map()).entries()).next = increaseCallCount;
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
});
}
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;
Object.hasOwnProperty = increaseCallCount;

parentPort.postMessage('done');

0 comments on commit a07bc82

Please sign in to comment.