Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 687ffcc

Browse filesBrowse files
aduh95RafaelGSS
authored andcommitted
lib: reset RegExp statics before running user code
Fixes: #43740 Backport-PR-URL: #43741 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> PR-URL: #44247 Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
1 parent 4700ee5 commit 687ffcc
Copy full SHA for 687ffcc

File tree

Expand file treeCollapse file tree

11 files changed

+136
-12
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

11 files changed

+136
-12
lines changed
Open diff view settings
Collapse file

‎lib/fs.js‎

Copy file name to clipboardExpand all lines: lib/fs.js
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ const {
3737
ObjectDefineProperty,
3838
Promise,
3939
ReflectApply,
40-
RegExpPrototypeExec,
4140
SafeMap,
4241
SafeSet,
4342
String,
@@ -90,6 +89,7 @@ const {
9089
promisify: {
9190
custom: kCustomPromisifiedSymbol,
9291
},
92+
SideEffectFreeRegExpPrototypeExec,
9393
} = require('internal/util');
9494
const {
9595
constants: {
@@ -2424,7 +2424,7 @@ if (isWindows) {
24242424
// slash.
24252425
const splitRootRe = /^(?:[a-zA-Z]:|[\\/]{2}[^\\/]+[\\/][^\\/]+)?[\\/]*/;
24262426
splitRoot = function splitRoot(str) {
2427-
return RegExpPrototypeExec(splitRootRe, str)[0];
2427+
return SideEffectFreeRegExpPrototypeExec(splitRootRe, str)[0];
24282428
};
24292429
} else {
24302430
splitRoot = function splitRoot(str) {
Collapse file

‎lib/internal/main/run_main_module.js‎

Copy file name to clipboardExpand all lines: lib/internal/main/run_main_module.js
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use strict';
22

3+
const { RegExpPrototypeExec } = primordials;
4+
35
const {
46
prepareMainThreadExecution,
57
markBootstrapComplete
@@ -9,6 +11,9 @@ prepareMainThreadExecution(true);
911

1012
markBootstrapComplete();
1113

14+
// Necessary to reset RegExp statics before user code runs.
15+
RegExpPrototypeExec(/^/, '');
16+
1217
// Note: this loads the module through the ESM loader if the module is
1318
// determined to be an ES module. This hangs from the CJS module loader
1419
// because we currently allow monkey-patching of the module loaders
Collapse file

‎lib/internal/main/worker_thread.js‎

Copy file name to clipboardExpand all lines: lib/internal/main/worker_thread.js
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const {
99
ArrayPrototypeSplice,
1010
ObjectDefineProperty,
1111
PromisePrototypeThen,
12+
RegExpPrototypeExec,
1213
globalThis: { Atomics },
1314
} = primordials;
1415

@@ -267,4 +268,7 @@ process._fatalException = workerOnGlobalUncaughtException;
267268

268269
markBootstrapComplete();
269270

271+
// Necessary to reset RegExp statics before user code runs.
272+
RegExpPrototypeExec(/^/, '');
273+
270274
port.start();
Collapse file

‎lib/internal/modules/esm/translators.js‎

Copy file name to clipboardExpand all lines: lib/internal/modules/esm/translators.js
+3-4Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const {
1111
SafeArrayIterator,
1212
SafeMap,
1313
SafeSet,
14-
StringPrototypeReplace,
14+
StringPrototypeReplaceAll,
1515
StringPrototypeSlice,
1616
StringPrototypeStartsWith,
1717
SyntaxErrorPrototype,
@@ -144,14 +144,13 @@ function enrichCJSError(err, content, filename) {
144144

145145
// Strategy for loading a node-style CommonJS module
146146
const isWindows = process.platform === 'win32';
147-
const winSepRegEx = /\//g;
148147
translators.set('commonjs', async function commonjsStrategy(url, source,
149148
isMain) {
150149
debug(`Translating CJSModule ${url}`);
151150

152151
let filename = internalURLModule.fileURLToPath(new URL(url));
153152
if (isWindows)
154-
filename = StringPrototypeReplace(filename, winSepRegEx, '\\');
153+
filename = StringPrototypeReplaceAll(filename, '/', '\\');
155154

156155
if (!cjsParse) await initCJSParse();
157156
const { module, exportNames } = cjsPreparseModuleExports(filename);
@@ -274,7 +273,7 @@ translators.set('json', async function jsonStrategy(url, source) {
274273
let module;
275274
if (pathname) {
276275
modulePath = isWindows ?
277-
StringPrototypeReplace(pathname, winSepRegEx, '\\') : pathname;
276+
StringPrototypeReplaceAll(pathname, '/', '\\') : pathname;
278277
module = CJSModule._cache[modulePath];
279278
if (module && module.loaded) {
280279
const exports = module.exports;
Collapse file

‎lib/internal/process/execution.js‎

Copy file name to clipboardExpand all lines: lib/internal/process/execution.js
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
const {
4+
RegExpPrototypeExec,
45
globalThis,
56
} = primordials;
67

@@ -45,6 +46,7 @@ function evalModule(source, print) {
4546
}
4647
const { loadESM } = require('internal/process/esm_loader');
4748
const { handleMainPromise } = require('internal/modules/run_main');
49+
RegExpPrototypeExec(/^/, ''); // Necessary to reset RegExp statics before user code runs.
4850
return handleMainPromise(loadESM((loader) => loader.eval(source)));
4951
}
5052

@@ -72,6 +74,7 @@ function evalScript(name, body, breakFirstLine, print) {
7274
return (main) => main();
7375
`;
7476
globalThis.__filename = name;
77+
RegExpPrototypeExec(/^/, ''); // Necessary to reset RegExp statics before user code runs.
7578
const result = module._compile(script, `${name}-wrapper`)(() =>
7679
require('vm').runInThisContext(body, {
7780
filename: name,
Collapse file

‎lib/internal/url.js‎

Copy file name to clipboardExpand all lines: lib/internal/url.js
+2-3Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const {
2323
StringPrototypeCharCodeAt,
2424
StringPrototypeIncludes,
2525
StringPrototypeReplace,
26+
StringPrototypeReplaceAll,
2627
StringPrototypeSlice,
2728
StringPrototypeSplit,
2829
StringPrototypeStartsWith,
@@ -1424,8 +1425,6 @@ function urlToHttpOptions(url) {
14241425
return options;
14251426
}
14261427

1427-
const forwardSlashRegEx = /\//g;
1428-
14291428
function getPathFromURLWin32(url) {
14301429
const hostname = url.hostname;
14311430
let pathname = url.pathname;
@@ -1440,7 +1439,7 @@ function getPathFromURLWin32(url) {
14401439
}
14411440
}
14421441
}
1443-
pathname = pathname.replace(forwardSlashRegEx, '\\');
1442+
pathname = StringPrototypeReplaceAll(pathname, '/', '\\');
14441443
pathname = decodeURIComponent(pathname);
14451444
if (hostname !== '') {
14461445
// If hostname is set, then we have a UNC path
Collapse file

‎lib/internal/util.js‎

Copy file name to clipboardExpand all lines: lib/internal/util.js
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ const {
77
ArrayPrototypeSlice,
88
ArrayPrototypeSort,
99
Error,
10+
FunctionPrototypeCall,
1011
ObjectCreate,
1112
ObjectDefineProperties,
1213
ObjectDefineProperty,
@@ -543,6 +544,21 @@ function setOwnProperty(obj, key, value) {
543544
});
544545
}
545546

547+
let internalGlobal;
548+
function getInternalGlobal() {
549+
if (internalGlobal == null) {
550+
// Lazy-load to avoid a circular dependency.
551+
const { runInNewContext } = require('vm');
552+
internalGlobal = runInNewContext('this', undefined, { contextName: 'internal' });
553+
}
554+
return internalGlobal;
555+
}
556+
557+
function SideEffectFreeRegExpPrototypeExec(regex, string) {
558+
const { RegExp: RegExpFromAnotherRealm } = getInternalGlobal();
559+
return FunctionPrototypeCall(RegExpFromAnotherRealm.prototype.exec, regex, string);
560+
}
561+
546562
module.exports = {
547563
assertCrypto,
548564
cachedResult,
@@ -557,6 +573,7 @@ module.exports = {
557573
filterDuplicateStrings,
558574
filterOwnProperties,
559575
getConstructorOf,
576+
getInternalGlobal,
560577
getSystemErrorMap,
561578
getSystemErrorName,
562579
isError,
@@ -567,6 +584,7 @@ module.exports = {
567584
normalizeEncoding,
568585
once,
569586
promisify,
587+
SideEffectFreeRegExpPrototypeExec,
570588
sleep,
571589
spliceOne,
572590
toUSVString,
Collapse file
+68Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('node:assert');
5+
const { spawnSync, spawn } = require('node:child_process');
6+
7+
assert.strictEqual(RegExp.$_, '');
8+
assert.strictEqual(RegExp.$0, undefined);
9+
assert.strictEqual(RegExp.$1, '');
10+
assert.strictEqual(RegExp.$2, '');
11+
assert.strictEqual(RegExp.$3, '');
12+
assert.strictEqual(RegExp.$4, '');
13+
assert.strictEqual(RegExp.$5, '');
14+
assert.strictEqual(RegExp.$6, '');
15+
assert.strictEqual(RegExp.$7, '');
16+
assert.strictEqual(RegExp.$8, '');
17+
assert.strictEqual(RegExp.$9, '');
18+
assert.strictEqual(RegExp.input, '');
19+
assert.strictEqual(RegExp.lastMatch, '');
20+
assert.strictEqual(RegExp.lastParen, '');
21+
assert.strictEqual(RegExp.leftContext, '');
22+
assert.strictEqual(RegExp.rightContext, '');
23+
assert.strictEqual(RegExp['$&'], '');
24+
assert.strictEqual(RegExp['$`'], '');
25+
assert.strictEqual(RegExp['$+'], '');
26+
assert.strictEqual(RegExp["$'"], '');
27+
28+
const allRegExpStatics =
29+
'RegExp.$_ + RegExp["$&"] + RegExp["$`"] + RegExp["$+"] + RegExp["$\'"] + ' +
30+
'RegExp.input + RegExp.lastMatch + RegExp.lastParen + ' +
31+
'RegExp.leftContext + RegExp.rightContext + ' +
32+
Array.from({ length: 10 }, (_, i) => `RegExp.$${i}`).join(' + ');
33+
34+
{
35+
const child = spawnSync(process.execPath,
36+
[ '-p', allRegExpStatics ],
37+
{ stdio: ['inherit', 'pipe', 'inherit'] });
38+
assert.match(child.stdout.toString(), /^undefined\r?\n$/);
39+
assert.strictEqual(child.status, 0);
40+
assert.strictEqual(child.signal, null);
41+
}
42+
43+
{
44+
const child = spawnSync(process.execPath,
45+
[ '-e', `console.log(${allRegExpStatics})`, '--input-type=module' ],
46+
{ stdio: ['inherit', 'pipe', 'inherit'] });
47+
assert.match(child.stdout.toString(), /^undefined\r?\n$/);
48+
assert.strictEqual(child.status, 0);
49+
assert.strictEqual(child.signal, null);
50+
}
51+
52+
{
53+
const child = spawn(process.execPath, [], { stdio: ['pipe', 'pipe', 'inherit'], encoding: 'utf8' });
54+
55+
let stdout = '';
56+
child.stdout.on('data', (chunk) => {
57+
stdout += chunk;
58+
});
59+
60+
child.on('exit', common.mustCall((status, signal) => {
61+
assert.match(stdout, /^undefined\r?\n$/);
62+
assert.strictEqual(status, 0);
63+
assert.strictEqual(signal, null);
64+
}));
65+
child.on('error', common.mustNotCall());
66+
67+
child.stdin.end(`console.log(${allRegExpStatics});\n`);
68+
}
Collapse file
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// We must load the CJS version here because the ESM wrapper call `hasIPv6`
2+
// which compiles a RegEx.
3+
// eslint-disable-next-line node-core/require-common-first
4+
import '../common/index.js';
5+
import assert from 'node:assert';
6+
7+
assert.strictEqual(RegExp.$_, '');
8+
assert.strictEqual(RegExp.$0, undefined);
9+
assert.strictEqual(RegExp.$1, '');
10+
assert.strictEqual(RegExp.$2, '');
11+
assert.strictEqual(RegExp.$3, '');
12+
assert.strictEqual(RegExp.$4, '');
13+
assert.strictEqual(RegExp.$5, '');
14+
assert.strictEqual(RegExp.$6, '');
15+
assert.strictEqual(RegExp.$7, '');
16+
assert.strictEqual(RegExp.$8, '');
17+
assert.strictEqual(RegExp.$9, '');
18+
assert.strictEqual(RegExp.input, '');
19+
assert.strictEqual(RegExp.lastMatch, '');
20+
assert.strictEqual(RegExp.lastParen, '');
21+
assert.strictEqual(RegExp.leftContext, '');
22+
assert.strictEqual(RegExp.rightContext, '');
23+
assert.strictEqual(RegExp['$&'], '');
24+
assert.strictEqual(RegExp['$`'], '');
25+
assert.strictEqual(RegExp['$+'], '');
26+
assert.strictEqual(RegExp["$'"], '');
Collapse file

‎test/parallel/test-vm-measure-memory-multi-context.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-vm-measure-memory-multi-context.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ expectExperimentalWarning();
2323
// We must hold on to the contexts here so that they
2424
// don't get GC'ed until the measurement is complete
2525
assert.strictEqual(arr.length, count);
26-
assertDetailedShape(result, count);
26+
assertDetailedShape(result, count + common.isWindows);
2727
}));
2828
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.