Skip to content

Commit 9b9b6d5

Browse files
aduh95danielleadams
authored andcommitted
domain: make node resilient to Array prototype tempering
Fixes: #36669 PR-URL: #36676 Reviewed-By: Rich Trott <[email protected]> Reviewed-By: Michaël Zasso <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 94afc3e commit 9b9b6d5

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

lib/domain.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ Domain.prototype.exit = function() {
319319
// Exit all domains until this one.
320320
ArrayPrototypeSplice(stack, index);
321321

322-
exports.active = stack[stack.length - 1];
322+
exports.active = stack.length === 0 ? undefined : stack[stack.length - 1];
323323
process.domain = exports.active;
324324
updateExceptionCapture();
325325
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const { spawn } = require('child_process');
5+
6+
const replProcess = spawn(process.argv0, ['--interactive'], {
7+
stdio: ['pipe', 'pipe', 'inherit'],
8+
windowsHide: true,
9+
});
10+
11+
replProcess.on('error', common.mustNotCall());
12+
13+
const replReadyState = (async function* () {
14+
let ready;
15+
const SPACE = ' '.charCodeAt();
16+
const BRACKET = '>'.charCodeAt();
17+
const DOT = '.'.charCodeAt();
18+
replProcess.stdout.on('data', (data) => {
19+
ready = data[data.length - 1] === SPACE && (
20+
data[data.length - 2] === BRACKET || (
21+
data[data.length - 2] === DOT &&
22+
data[data.length - 3] === DOT &&
23+
data[data.length - 4] === DOT
24+
));
25+
});
26+
27+
const processCrashed = new Promise((resolve, reject) =>
28+
replProcess.on('exit', reject)
29+
);
30+
while (true) {
31+
await Promise.race([new Promise(setImmediate), processCrashed]);
32+
if (ready) {
33+
ready = false;
34+
yield;
35+
}
36+
}
37+
})();
38+
async function writeLn(data, expectedOutput) {
39+
await replReadyState.next();
40+
if (expectedOutput) {
41+
replProcess.stdout.once('data', common.mustCall((data) =>
42+
assert.match(data.toString('utf8'), expectedOutput)
43+
));
44+
}
45+
await new Promise((resolve, reject) => replProcess.stdin.write(
46+
`${data}\n`,
47+
(err) => (err ? reject(err) : resolve())
48+
));
49+
}
50+
51+
async function main() {
52+
await writeLn(
53+
'Object.defineProperty(Array.prototype, "-1", ' +
54+
'{ get() { return this[this.length - 1]; } });'
55+
);
56+
57+
await writeLn(
58+
'[3, 2, 1][-1];',
59+
/^1\n(>\s)?$/
60+
);
61+
await writeLn('.exit');
62+
63+
assert(!replProcess.connected);
64+
}
65+
66+
main().then(common.mustCall());

0 commit comments

Comments
 (0)