repl: improve robustness wrt to prototype pollution
PR-URL: https://github.com/nodejs/node/pull/45604 Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
b4f8186657
commit
1c3ba4c5fa
@ -28,14 +28,15 @@ const {
|
|||||||
ReflectGetOwnPropertyDescriptor,
|
ReflectGetOwnPropertyDescriptor,
|
||||||
ReflectOwnKeys,
|
ReflectOwnKeys,
|
||||||
RegExpPrototypeExec,
|
RegExpPrototypeExec,
|
||||||
RegExpPrototypeSymbolReplace,
|
|
||||||
SafeMap,
|
SafeMap,
|
||||||
SafePromiseAll,
|
SafePromiseAllReturnArrayLike,
|
||||||
|
SafePromiseAllReturnVoid,
|
||||||
String,
|
String,
|
||||||
StringFromCharCode,
|
StringFromCharCode,
|
||||||
StringPrototypeEndsWith,
|
StringPrototypeEndsWith,
|
||||||
StringPrototypeIncludes,
|
StringPrototypeIncludes,
|
||||||
StringPrototypeRepeat,
|
StringPrototypeRepeat,
|
||||||
|
StringPrototypeReplaceAll,
|
||||||
StringPrototypeSlice,
|
StringPrototypeSlice,
|
||||||
StringPrototypeSplit,
|
StringPrototypeSplit,
|
||||||
StringPrototypeStartsWith,
|
StringPrototypeStartsWith,
|
||||||
@ -53,7 +54,7 @@ const Repl = require('repl');
|
|||||||
const vm = require('vm');
|
const vm = require('vm');
|
||||||
const { fileURLToPath } = require('internal/url');
|
const { fileURLToPath } = require('internal/url');
|
||||||
|
|
||||||
const { customInspectSymbol } = require('internal/util');
|
const { customInspectSymbol, SideEffectFreeRegExpPrototypeSymbolReplace } = require('internal/util');
|
||||||
const { inspect: utilInspect } = require('internal/util/inspect');
|
const { inspect: utilInspect } = require('internal/util/inspect');
|
||||||
const debuglog = require('internal/util/debuglog').debuglog('inspect');
|
const debuglog = require('internal/util/debuglog').debuglog('inspect');
|
||||||
|
|
||||||
@ -121,7 +122,7 @@ const {
|
|||||||
} = internalBinding('builtins');
|
} = internalBinding('builtins');
|
||||||
const NATIVES = internalBinding('natives');
|
const NATIVES = internalBinding('natives');
|
||||||
function isNativeUrl(url) {
|
function isNativeUrl(url) {
|
||||||
url = RegExpPrototypeSymbolReplace(/\.js$/, url, '');
|
url = SideEffectFreeRegExpPrototypeSymbolReplace(/\.js$/, url, '');
|
||||||
|
|
||||||
return StringPrototypeStartsWith(url, 'node:internal/') ||
|
return StringPrototypeStartsWith(url, 'node:internal/') ||
|
||||||
ArrayPrototypeIncludes(PUBLIC_BUILTINS, url) ||
|
ArrayPrototypeIncludes(PUBLIC_BUILTINS, url) ||
|
||||||
@ -159,8 +160,8 @@ function markSourceColumn(sourceText, position, useColors) {
|
|||||||
|
|
||||||
// Colourize char if stdout supports colours
|
// Colourize char if stdout supports colours
|
||||||
if (useColors) {
|
if (useColors) {
|
||||||
tail = RegExpPrototypeSymbolReplace(/(.+?)([^\w]|$)/, tail,
|
tail = SideEffectFreeRegExpPrototypeSymbolReplace(/(.+?)([^\w]|$)/, tail,
|
||||||
'\u001b[32m$1\u001b[39m$2');
|
'\u001b[32m$1\u001b[39m$2');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return source line with coloured char at `position`
|
// Return source line with coloured char at `position`
|
||||||
@ -340,9 +341,9 @@ class ScopeSnapshot {
|
|||||||
StringPrototypeSlice(this.type, 1);
|
StringPrototypeSlice(this.type, 1);
|
||||||
const name = this.name ? `<${this.name}>` : '';
|
const name = this.name ? `<${this.name}>` : '';
|
||||||
const prefix = `${type}${name} `;
|
const prefix = `${type}${name} `;
|
||||||
return RegExpPrototypeSymbolReplace(/^Map /,
|
return SideEffectFreeRegExpPrototypeSymbolReplace(/^Map /,
|
||||||
utilInspect(this.properties, opts),
|
utilInspect(this.properties, opts),
|
||||||
prefix);
|
prefix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -517,7 +518,7 @@ function createRepl(inspector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
loadScopes() {
|
loadScopes() {
|
||||||
return SafePromiseAll(
|
return SafePromiseAllReturnArrayLike(
|
||||||
ArrayPrototypeFilter(
|
ArrayPrototypeFilter(
|
||||||
this.scopeChain,
|
this.scopeChain,
|
||||||
(scope) => scope.type !== 'global'
|
(scope) => scope.type !== 'global'
|
||||||
@ -656,14 +657,14 @@ function createRepl(inspector) {
|
|||||||
(error) => `<${error.message}>`);
|
(error) => `<${error.message}>`);
|
||||||
const lastIndex = watchedExpressions.length - 1;
|
const lastIndex = watchedExpressions.length - 1;
|
||||||
|
|
||||||
const values = await SafePromiseAll(watchedExpressions, inspectValue);
|
const values = await SafePromiseAllReturnArrayLike(watchedExpressions, inspectValue);
|
||||||
const lines = ArrayPrototypeMap(watchedExpressions, (expr, idx) => {
|
const lines = ArrayPrototypeMap(watchedExpressions, (expr, idx) => {
|
||||||
const prefix = `${leftPad(idx, ' ', lastIndex)}: ${expr} =`;
|
const prefix = `${leftPad(idx, ' ', lastIndex)}: ${expr} =`;
|
||||||
const value = inspect(values[idx]);
|
const value = inspect(values[idx]);
|
||||||
if (!StringPrototypeIncludes(value, '\n')) {
|
if (!StringPrototypeIncludes(value, '\n')) {
|
||||||
return `${prefix} ${value}`;
|
return `${prefix} ${value}`;
|
||||||
}
|
}
|
||||||
return `${prefix}\n ${RegExpPrototypeSymbolReplace(/\n/g, value, '\n ')}`;
|
return `${prefix}\n ${StringPrototypeReplaceAll(value, '\n', '\n ')}`;
|
||||||
});
|
});
|
||||||
const valueList = ArrayPrototypeJoin(lines, '\n');
|
const valueList = ArrayPrototypeJoin(lines, '\n');
|
||||||
return verbose ? `Watchers:\n${valueList}\n` : valueList;
|
return verbose ? `Watchers:\n${valueList}\n` : valueList;
|
||||||
@ -805,8 +806,8 @@ function createRepl(inspector) {
|
|||||||
registerBreakpoint);
|
registerBreakpoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
const escapedPath = RegExpPrototypeSymbolReplace(/([/\\.?*()^${}|[\]])/g,
|
const escapedPath = SideEffectFreeRegExpPrototypeSymbolReplace(/([/\\.?*()^${}|[\]])/g,
|
||||||
script, '\\$1');
|
script, '\\$1');
|
||||||
const urlRegex = `^(.*[\\/\\\\])?${escapedPath}$`;
|
const urlRegex = `^(.*[\\/\\\\])?${escapedPath}$`;
|
||||||
|
|
||||||
return PromisePrototypeThen(
|
return PromisePrototypeThen(
|
||||||
@ -860,9 +861,9 @@ function createRepl(inspector) {
|
|||||||
location.lineNumber + 1));
|
location.lineNumber + 1));
|
||||||
if (!newBreakpoints.length) return PromiseResolve();
|
if (!newBreakpoints.length) return PromiseResolve();
|
||||||
return PromisePrototypeThen(
|
return PromisePrototypeThen(
|
||||||
SafePromiseAll(newBreakpoints),
|
SafePromiseAllReturnVoid(newBreakpoints),
|
||||||
(results) => {
|
() => {
|
||||||
print(`${results.length} breakpoints restored.`);
|
print(`${newBreakpoints.length} breakpoints restored.`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -896,7 +897,7 @@ function createRepl(inspector) {
|
|||||||
|
|
||||||
inspector.suspendReplWhile(() =>
|
inspector.suspendReplWhile(() =>
|
||||||
PromisePrototypeThen(
|
PromisePrototypeThen(
|
||||||
SafePromiseAll([formatWatchers(true), selectedFrame.list(2)]),
|
SafePromiseAllReturnArrayLike([formatWatchers(true), selectedFrame.list(2)]),
|
||||||
({ 0: watcherList, 1: context }) => {
|
({ 0: watcherList, 1: context }) => {
|
||||||
const breakContext = watcherList ?
|
const breakContext = watcherList ?
|
||||||
`${watcherList}\n${inspect(context)}` :
|
`${watcherList}\n${inspect(context)}` :
|
||||||
|
@ -23,13 +23,24 @@ const {
|
|||||||
ReflectApply,
|
ReflectApply,
|
||||||
ReflectConstruct,
|
ReflectConstruct,
|
||||||
RegExpPrototypeExec,
|
RegExpPrototypeExec,
|
||||||
|
RegExpPrototypeGetDotAll,
|
||||||
|
RegExpPrototypeGetGlobal,
|
||||||
|
RegExpPrototypeGetHasIndices,
|
||||||
|
RegExpPrototypeGetIgnoreCase,
|
||||||
|
RegExpPrototypeGetMultiline,
|
||||||
|
RegExpPrototypeGetSticky,
|
||||||
|
RegExpPrototypeGetUnicode,
|
||||||
|
RegExpPrototypeGetSource,
|
||||||
SafeMap,
|
SafeMap,
|
||||||
SafeSet,
|
SafeSet,
|
||||||
|
SafeWeakMap,
|
||||||
StringPrototypeReplace,
|
StringPrototypeReplace,
|
||||||
StringPrototypeToLowerCase,
|
StringPrototypeToLowerCase,
|
||||||
StringPrototypeToUpperCase,
|
StringPrototypeToUpperCase,
|
||||||
Symbol,
|
Symbol,
|
||||||
SymbolFor,
|
SymbolFor,
|
||||||
|
SymbolReplace,
|
||||||
|
SymbolSplit,
|
||||||
} = primordials;
|
} = primordials;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -646,6 +657,35 @@ function SideEffectFreeRegExpPrototypeExec(regex, string) {
|
|||||||
return FunctionPrototypeCall(RegExpFromAnotherRealm.prototype.exec, regex, string);
|
return FunctionPrototypeCall(RegExpFromAnotherRealm.prototype.exec, regex, string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const crossRelmRegexes = new SafeWeakMap();
|
||||||
|
function getCrossRelmRegex(regex) {
|
||||||
|
const cached = crossRelmRegexes.get(regex);
|
||||||
|
if (cached) return cached;
|
||||||
|
|
||||||
|
let flagString = '';
|
||||||
|
if (RegExpPrototypeGetHasIndices(regex)) flagString += 'd';
|
||||||
|
if (RegExpPrototypeGetGlobal(regex)) flagString += 'g';
|
||||||
|
if (RegExpPrototypeGetIgnoreCase(regex)) flagString += 'i';
|
||||||
|
if (RegExpPrototypeGetMultiline(regex)) flagString += 'm';
|
||||||
|
if (RegExpPrototypeGetDotAll(regex)) flagString += 's';
|
||||||
|
if (RegExpPrototypeGetUnicode(regex)) flagString += 'u';
|
||||||
|
if (RegExpPrototypeGetSticky(regex)) flagString += 'y';
|
||||||
|
|
||||||
|
const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal();
|
||||||
|
const crossRelmRegex = new RegExpFromAnotherRealm(RegExpPrototypeGetSource(regex), flagString);
|
||||||
|
crossRelmRegexes.set(regex, crossRelmRegex);
|
||||||
|
return crossRelmRegex;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SideEffectFreeRegExpPrototypeSymbolReplace(regex, string, replacement) {
|
||||||
|
return getCrossRelmRegex(regex)[SymbolReplace](string, replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SideEffectFreeRegExpPrototypeSymbolSplit(regex, string, limit = undefined) {
|
||||||
|
return getCrossRelmRegex(regex)[SymbolSplit](string, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function isArrayBufferDetached(value) {
|
function isArrayBufferDetached(value) {
|
||||||
if (ArrayBufferPrototypeGetByteLength(value) === 0) {
|
if (ArrayBufferPrototypeGetByteLength(value) === 0) {
|
||||||
return _isArrayBufferDetached(value);
|
return _isArrayBufferDetached(value);
|
||||||
@ -684,6 +724,8 @@ module.exports = {
|
|||||||
once,
|
once,
|
||||||
promisify,
|
promisify,
|
||||||
SideEffectFreeRegExpPrototypeExec,
|
SideEffectFreeRegExpPrototypeExec,
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolReplace,
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolSplit,
|
||||||
sleep,
|
sleep,
|
||||||
spliceOne,
|
spliceOne,
|
||||||
toUSVString,
|
toUSVString,
|
||||||
|
18
lib/repl.js
18
lib/repl.js
@ -77,8 +77,6 @@ const {
|
|||||||
ReflectApply,
|
ReflectApply,
|
||||||
RegExp,
|
RegExp,
|
||||||
RegExpPrototypeExec,
|
RegExpPrototypeExec,
|
||||||
RegExpPrototypeSymbolReplace,
|
|
||||||
RegExpPrototypeSymbolSplit,
|
|
||||||
SafePromiseRace,
|
SafePromiseRace,
|
||||||
SafeSet,
|
SafeSet,
|
||||||
SafeWeakSet,
|
SafeWeakSet,
|
||||||
@ -111,7 +109,9 @@ const {
|
|||||||
const {
|
const {
|
||||||
decorateErrorStack,
|
decorateErrorStack,
|
||||||
isError,
|
isError,
|
||||||
deprecate
|
deprecate,
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolReplace,
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolSplit,
|
||||||
} = require('internal/util');
|
} = require('internal/util');
|
||||||
const { inspect } = require('internal/util/inspect');
|
const { inspect } = require('internal/util/inspect');
|
||||||
const vm = require('vm');
|
const vm = require('vm');
|
||||||
@ -455,7 +455,7 @@ function REPLServer(prompt,
|
|||||||
|
|
||||||
// Remove all "await"s and attempt running the script
|
// Remove all "await"s and attempt running the script
|
||||||
// in order to detect if error is truly non recoverable
|
// in order to detect if error is truly non recoverable
|
||||||
const fallbackCode = RegExpPrototypeSymbolReplace(/\bawait\b/g, code, '');
|
const fallbackCode = SideEffectFreeRegExpPrototypeSymbolReplace(/\bawait\b/g, code, '');
|
||||||
try {
|
try {
|
||||||
vm.createScript(fallbackCode, {
|
vm.createScript(fallbackCode, {
|
||||||
filename: file,
|
filename: file,
|
||||||
@ -680,22 +680,22 @@ function REPLServer(prompt,
|
|||||||
if (e.stack) {
|
if (e.stack) {
|
||||||
if (e.name === 'SyntaxError') {
|
if (e.name === 'SyntaxError') {
|
||||||
// Remove stack trace.
|
// Remove stack trace.
|
||||||
e.stack = RegExpPrototypeSymbolReplace(
|
e.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
|
||||||
/^\s+at\s.*\n?/gm,
|
/^\s+at\s.*\n?/gm,
|
||||||
RegExpPrototypeSymbolReplace(/^REPL\d+:\d+\r?\n/, e.stack, ''),
|
SideEffectFreeRegExpPrototypeSymbolReplace(/^REPL\d+:\d+\r?\n/, e.stack, ''),
|
||||||
'');
|
'');
|
||||||
const importErrorStr = 'Cannot use import statement outside a ' +
|
const importErrorStr = 'Cannot use import statement outside a ' +
|
||||||
'module';
|
'module';
|
||||||
if (StringPrototypeIncludes(e.message, importErrorStr)) {
|
if (StringPrototypeIncludes(e.message, importErrorStr)) {
|
||||||
e.message = 'Cannot use import statement inside the Node.js ' +
|
e.message = 'Cannot use import statement inside the Node.js ' +
|
||||||
'REPL, alternatively use dynamic import';
|
'REPL, alternatively use dynamic import';
|
||||||
e.stack = RegExpPrototypeSymbolReplace(
|
e.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
|
||||||
/SyntaxError:.*\n/,
|
/SyntaxError:.*\n/,
|
||||||
e.stack,
|
e.stack,
|
||||||
`SyntaxError: ${e.message}\n`);
|
`SyntaxError: ${e.message}\n`);
|
||||||
}
|
}
|
||||||
} else if (self.replMode === module.exports.REPL_MODE_STRICT) {
|
} else if (self.replMode === module.exports.REPL_MODE_STRICT) {
|
||||||
e.stack = RegExpPrototypeSymbolReplace(
|
e.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
|
||||||
/(\s+at\s+REPL\d+:)(\d+)/,
|
/(\s+at\s+REPL\d+:)(\d+)/,
|
||||||
e.stack,
|
e.stack,
|
||||||
(_, pre, line) => pre + (line - 1)
|
(_, pre, line) => pre + (line - 1)
|
||||||
@ -727,7 +727,7 @@ function REPLServer(prompt,
|
|||||||
if (errStack === '') {
|
if (errStack === '') {
|
||||||
errStack = self.writer(e);
|
errStack = self.writer(e);
|
||||||
}
|
}
|
||||||
const lines = RegExpPrototypeSymbolSplit(/(?<=\n)/, errStack);
|
const lines = SideEffectFreeRegExpPrototypeSymbolSplit(/(?<=\n)/, errStack);
|
||||||
let matched = false;
|
let matched = false;
|
||||||
|
|
||||||
errStack = '';
|
errStack = '';
|
||||||
|
@ -5,6 +5,7 @@ const { mustNotCall } = require('../common');
|
|||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
RegExpPrototypeExec,
|
||||||
RegExpPrototypeSymbolReplace,
|
RegExpPrototypeSymbolReplace,
|
||||||
RegExpPrototypeSymbolSearch,
|
RegExpPrototypeSymbolSearch,
|
||||||
RegExpPrototypeSymbolSplit,
|
RegExpPrototypeSymbolSplit,
|
||||||
@ -12,6 +13,12 @@ const {
|
|||||||
hardenRegExp,
|
hardenRegExp,
|
||||||
} = require('internal/test/binding').primordials;
|
} = require('internal/test/binding').primordials;
|
||||||
|
|
||||||
|
const {
|
||||||
|
SideEffectFreeRegExpPrototypeExec,
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolReplace,
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolSplit,
|
||||||
|
} = require('internal/util');
|
||||||
|
|
||||||
|
|
||||||
Object.defineProperties(RegExp.prototype, {
|
Object.defineProperties(RegExp.prototype, {
|
||||||
[Symbol.match]: {
|
[Symbol.match]: {
|
||||||
@ -89,14 +96,46 @@ hardenRegExp(hardenRegExp(/1/));
|
|||||||
// IMO there are no valid use cases in node core to use RegExpPrototypeSymbolMatch
|
// IMO there are no valid use cases in node core to use RegExpPrototypeSymbolMatch
|
||||||
// or RegExpPrototypeSymbolMatchAll, they are inherently unsafe.
|
// or RegExpPrototypeSymbolMatchAll, they are inherently unsafe.
|
||||||
|
|
||||||
|
assert.strictEqual(RegExpPrototypeExec(/foo/, 'bar'), null);
|
||||||
|
assert.strictEqual(RegExpPrototypeExec(hardenRegExp(/foo/), 'bar'), null);
|
||||||
|
assert.strictEqual(SideEffectFreeRegExpPrototypeExec(/foo/, 'bar'), null);
|
||||||
|
assert.strictEqual(SideEffectFreeRegExpPrototypeExec(hardenRegExp(/foo/), 'bar'), null);
|
||||||
|
{
|
||||||
|
const expected = ['bar'];
|
||||||
|
Object.defineProperties(expected, {
|
||||||
|
index: { __proto__: null, configurable: true, writable: true, enumerable: true, value: 0 },
|
||||||
|
input: { __proto__: null, configurable: true, writable: true, enumerable: true, value: 'bar' },
|
||||||
|
groups: { __proto__: null, configurable: true, writable: true, enumerable: true },
|
||||||
|
});
|
||||||
|
const actual = SideEffectFreeRegExpPrototypeExec(/bar/, 'bar');
|
||||||
|
|
||||||
|
// assert.deepStrictEqual(actual, expected) doesn't work for cross-realm comparison.
|
||||||
|
|
||||||
|
assert.strictEqual(Array.isArray(actual), Array.isArray(expected));
|
||||||
|
assert.deepStrictEqual(Reflect.ownKeys(actual), Reflect.ownKeys(expected));
|
||||||
|
for (const key of Reflect.ownKeys(expected)) {
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
Reflect.getOwnPropertyDescriptor(actual, key),
|
||||||
|
Reflect.getOwnPropertyDescriptor(expected, key),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
const myRegex = hardenRegExp(/a/);
|
const myRegex = hardenRegExp(/a/);
|
||||||
assert.strictEqual(RegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'bear');
|
assert.strictEqual(RegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'bear');
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
const myRegex = /a/;
|
||||||
|
assert.strictEqual(SideEffectFreeRegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'bear');
|
||||||
|
}
|
||||||
{
|
{
|
||||||
const myRegex = hardenRegExp(/a/g);
|
const myRegex = hardenRegExp(/a/g);
|
||||||
assert.strictEqual(RegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'beer');
|
assert.strictEqual(RegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'beer');
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
const myRegex = /a/g;
|
||||||
|
assert.strictEqual(SideEffectFreeRegExpPrototypeSymbolReplace(myRegex, 'baar', 'e'), 'beer');
|
||||||
|
}
|
||||||
{
|
{
|
||||||
const myRegex = hardenRegExp(/a/);
|
const myRegex = hardenRegExp(/a/);
|
||||||
assert.strictEqual(RegExpPrototypeSymbolSearch(myRegex, 'baar'), 1);
|
assert.strictEqual(RegExpPrototypeSymbolSearch(myRegex, 'baar'), 1);
|
||||||
@ -109,6 +148,22 @@ hardenRegExp(hardenRegExp(/1/));
|
|||||||
const myRegex = hardenRegExp(/a/);
|
const myRegex = hardenRegExp(/a/);
|
||||||
assert.deepStrictEqual(RegExpPrototypeSymbolSplit(myRegex, 'baar', 0), []);
|
assert.deepStrictEqual(RegExpPrototypeSymbolSplit(myRegex, 'baar', 0), []);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
const myRegex = /a/;
|
||||||
|
const expected = [];
|
||||||
|
const actual = SideEffectFreeRegExpPrototypeSymbolSplit(myRegex, 'baar', 0);
|
||||||
|
|
||||||
|
// assert.deepStrictEqual(actual, expected) doesn't work for cross-realm comparison.
|
||||||
|
|
||||||
|
assert.strictEqual(Array.isArray(actual), Array.isArray(expected));
|
||||||
|
assert.deepStrictEqual(Reflect.ownKeys(actual), Reflect.ownKeys(expected));
|
||||||
|
for (const key of Reflect.ownKeys(expected)) {
|
||||||
|
assert.deepStrictEqual(
|
||||||
|
Reflect.getOwnPropertyDescriptor(actual, key),
|
||||||
|
Reflect.getOwnPropertyDescriptor(expected, key),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
{
|
{
|
||||||
const myRegex = hardenRegExp(/a/);
|
const myRegex = hardenRegExp(/a/);
|
||||||
assert.deepStrictEqual(RegExpPrototypeSymbolSplit(myRegex, 'baar', 1), ['b']);
|
assert.deepStrictEqual(RegExpPrototypeSymbolSplit(myRegex, 'baar', 1), ['b']);
|
||||||
|
@ -40,6 +40,23 @@ const allRegExpStatics =
|
|||||||
assert.strictEqual(child.signal, null);
|
assert.strictEqual(child.signal, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const child = spawnSync(process.execPath,
|
||||||
|
[ '--expose-internals', '-p', `const {
|
||||||
|
SideEffectFreeRegExpPrototypeExec,
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolReplace,
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolSplit,
|
||||||
|
} = require("internal/util");
|
||||||
|
SideEffectFreeRegExpPrototypeExec(/foo/, "foo");
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolReplace(/o/, "foo", "a");
|
||||||
|
SideEffectFreeRegExpPrototypeSymbolSplit(/o/, "foo");
|
||||||
|
${allRegExpStatics}` ],
|
||||||
|
{ stdio: ['inherit', 'pipe', 'inherit'] });
|
||||||
|
assert.match(child.stdout.toString(), /^undefined\r?\n$/);
|
||||||
|
assert.strictEqual(child.status, 0);
|
||||||
|
assert.strictEqual(child.signal, null);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const child = spawnSync(process.execPath,
|
const child = spawnSync(process.execPath,
|
||||||
[ '-e', `console.log(${allRegExpStatics})`, '--input-type=module' ],
|
[ '-e', `console.log(${allRegExpStatics})`, '--input-type=module' ],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user