Skip to content

Commit

Permalink
bootstrap: clean up inspector console methods during serialization
Browse files Browse the repository at this point in the history
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 9c5c145
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 0 deletions.
27 changes: 27 additions & 0 deletions lib/internal/console/constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const {
SafeArrayIterator,
SafeMap,
SafeWeakMap,
SafeSet,
StringPrototypeIncludes,
StringPrototypePadStart,
StringPrototypeRepeat,
Expand Down Expand Up @@ -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 = {
Expand Down
9 changes: 9 additions & 0 deletions test/fixtures/snapshot/console.js
Original file line number Diff line number Diff line change
@@ -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));
});
62 changes: 62 additions & 0 deletions test/parallel/test-snapshot-console.js
Original file line number Diff line number Diff line change
@@ -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.