Skip to content

Commit 9c5c145

Browse files
joyeecheungRafaelGSS
authored andcommitted
bootstrap: clean up inspector console methods during serialization
Some console methods are created by the V8 inspector after an inspector client is created, reset them to undefined during sereialization to avoid holding on to invalid references in the snapshot. V8 will take care of the re-initialization when another inspector client is created during deserialization. PR-URL: #44279 Fixes: nodejs/node-v8#237 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
1 parent 2baf532 commit 9c5c145

File tree

3 files changed

+98
-0
lines changed

3 files changed

+98
-0
lines changed

lib/internal/console/constructor.js

+27
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const {
2828
SafeArrayIterator,
2929
SafeMap,
3030
SafeWeakMap,
31+
SafeSet,
3132
StringPrototypeIncludes,
3233
StringPrototypePadStart,
3334
StringPrototypeRepeat,
@@ -687,6 +688,32 @@ Console.prototype.groupCollapsed = Console.prototype.group;
687688
function initializeGlobalConsole(globalConsole) {
688689
globalConsole[kBindStreamsLazy](process);
689690
globalConsole[kBindProperties](true, 'auto');
691+
692+
const {
693+
addSerializeCallback,
694+
isBuildingSnapshot,
695+
} = require('v8').startupSnapshot;
696+
697+
if (!internalBinding('config').hasInspector || !isBuildingSnapshot()) {
698+
return;
699+
}
700+
const { console: consoleFromVM } = internalBinding('inspector');
701+
const nodeConsoleKeys = ObjectKeys(Console.prototype);
702+
const vmConsoleKeys = ObjectKeys(consoleFromVM);
703+
const originalKeys = new SafeSet(vmConsoleKeys.concat(nodeConsoleKeys));
704+
const inspectorConsoleKeys = new SafeSet();
705+
for (const key of ObjectKeys(globalConsole)) {
706+
if (!originalKeys.has(key)) {
707+
inspectorConsoleKeys.add(key);
708+
}
709+
}
710+
// During deserialization these should be reinstalled to console by
711+
// V8 when the inspector client is created.
712+
addSerializeCallback(() => {
713+
for (const key of inspectorConsoleKeys) {
714+
globalConsole[key] = undefined;
715+
}
716+
});
690717
}
691718

692719
module.exports = {

test/fixtures/snapshot/console.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const {
2+
setDeserializeMainFunction,
3+
} = require('v8').startupSnapshot;
4+
5+
console.log(JSON.stringify(Object.keys(console), null, 2));
6+
7+
setDeserializeMainFunction(() => {
8+
console.log(JSON.stringify(Object.keys(console), null, 2));
9+
});
+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
'use strict';
2+
3+
// TODO(joyeecheung): remove the flag when it is turned on by default in V8.
4+
// Flags: --experimental-async-stack-tagging-api
5+
// This tests the console works in the deserialized snapshot.
6+
7+
const common = require('../common');
8+
common.skipIfInspectorDisabled();
9+
10+
const assert = require('assert');
11+
const { spawnSync } = require('child_process');
12+
const tmpdir = require('../common/tmpdir');
13+
const fixtures = require('../common/fixtures');
14+
const path = require('path');
15+
const fs = require('fs');
16+
17+
tmpdir.refresh();
18+
const blobPath = path.join(tmpdir.path, 'snapshot.blob');
19+
const entry = fixtures.path('snapshot', 'console.js');
20+
21+
{
22+
const child = spawnSync(process.execPath, [
23+
'--experimental-async-stack-tagging-api',
24+
'--snapshot-blob',
25+
blobPath,
26+
'--build-snapshot',
27+
entry,
28+
], {
29+
cwd: tmpdir.path
30+
});
31+
const stdout = child.stdout.toString();
32+
if (child.status !== 0) {
33+
console.log(stdout);
34+
console.log(child.stderr.toString());
35+
assert.strictEqual(child.status, 0);
36+
}
37+
assert.deepStrictEqual(Object.keys(console), JSON.parse(stdout));
38+
const stats = fs.statSync(path.join(tmpdir.path, 'snapshot.blob'));
39+
assert(stats.isFile());
40+
}
41+
42+
{
43+
const child = spawnSync(process.execPath, [
44+
'--experimental-async-stack-tagging-api',
45+
'--snapshot-blob',
46+
blobPath,
47+
], {
48+
cwd: tmpdir.path,
49+
env: {
50+
...process.env,
51+
}
52+
});
53+
54+
const stdout = child.stdout.toString();
55+
if (child.status !== 0) {
56+
console.log(stdout);
57+
console.log(child.stderr.toString());
58+
assert.strictEqual(child.status, 0);
59+
}
60+
assert.deepStrictEqual(Object.keys(console), JSON.parse(stdout));
61+
assert.strictEqual(child.status, 0);
62+
}

0 commit comments

Comments
 (0)