Skip to content
Permalink
Browse files
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>
  • Loading branch information
joyeecheung authored and RafaelGSS committed Sep 26, 2022
1 parent 2baf532 commit 9c5c1459a812c7780b8bb3256c646ce3006dc3e6
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 0 deletions.
@@ -28,6 +28,7 @@ const {
SafeArrayIterator,
SafeMap,
SafeWeakMap,
SafeSet,
StringPrototypeIncludes,
StringPrototypePadStart,
StringPrototypeRepeat,
@@ -687,6 +688,32 @@ Console.prototype.groupCollapsed = Console.prototype.group;
function initializeGlobalConsole(globalConsole) {
globalConsole[kBindStreamsLazy](process);
globalConsole[kBindProperties](true, 'auto');

const {
addSerializeCallback,
isBuildingSnapshot,
} = require('v8').startupSnapshot;

if (!internalBinding('config').hasInspector || !isBuildingSnapshot()) {
return;
}
const { console: consoleFromVM } = internalBinding('inspector');
const nodeConsoleKeys = ObjectKeys(Console.prototype);
const vmConsoleKeys = ObjectKeys(consoleFromVM);
const originalKeys = new SafeSet(vmConsoleKeys.concat(nodeConsoleKeys));
const inspectorConsoleKeys = new SafeSet();
for (const key of ObjectKeys(globalConsole)) {
if (!originalKeys.has(key)) {
inspectorConsoleKeys.add(key);
}
}
// During deserialization these should be reinstalled to console by
// V8 when the inspector client is created.
addSerializeCallback(() => {
for (const key of inspectorConsoleKeys) {
globalConsole[key] = undefined;
}
});
}

module.exports = {
@@ -0,0 +1,9 @@
const {
setDeserializeMainFunction,
} = require('v8').startupSnapshot;

console.log(JSON.stringify(Object.keys(console), null, 2));

setDeserializeMainFunction(() => {
console.log(JSON.stringify(Object.keys(console), null, 2));
});
@@ -0,0 +1,62 @@
'use strict';

// TODO(joyeecheung): remove the flag when it is turned on by default in V8.
// Flags: --experimental-async-stack-tagging-api
// This tests the console works in the deserialized snapshot.

const common = require('../common');
common.skipIfInspectorDisabled();

const assert = require('assert');
const { spawnSync } = require('child_process');
const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
const path = require('path');
const fs = require('fs');

tmpdir.refresh();
const blobPath = path.join(tmpdir.path, 'snapshot.blob');
const entry = fixtures.path('snapshot', 'console.js');

{
const child = spawnSync(process.execPath, [
'--experimental-async-stack-tagging-api',
'--snapshot-blob',
blobPath,
'--build-snapshot',
entry,
], {
cwd: tmpdir.path
});
const stdout = child.stdout.toString();
if (child.status !== 0) {
console.log(stdout);
console.log(child.stderr.toString());
assert.strictEqual(child.status, 0);
}
assert.deepStrictEqual(Object.keys(console), JSON.parse(stdout));
const stats = fs.statSync(path.join(tmpdir.path, 'snapshot.blob'));
assert(stats.isFile());
}

{
const child = spawnSync(process.execPath, [
'--experimental-async-stack-tagging-api',
'--snapshot-blob',
blobPath,
], {
cwd: tmpdir.path,
env: {
...process.env,
}
});

const stdout = child.stdout.toString();
if (child.status !== 0) {
console.log(stdout);
console.log(child.stderr.toString());
assert.strictEqual(child.status, 0);
}
assert.deepStrictEqual(Object.keys(console), JSON.parse(stdout));
assert.strictEqual(child.status, 0);
}

0 comments on commit 9c5c145

Please sign in to comment.