Skip to content

Commit 87d7845

Browse files
joyeecheungruyadorno
authored andcommitted
bootstrap: fixup Error.stackTraceLimit for user-land snapshot
It's difficult for V8 to handle Error.stackTraceLimit in the snapshot, so delete it from the Error constructor if it's present before snapshot serialization, and re-install it after deserialization. In addition try not to touch it from our internals during snapshot building in the first place by updating isErrorStackTraceLimitWritable(). PR-URL: #44203 Reviewed-By: Chengzhong Wu <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]>
1 parent 40b817c commit 87d7845

6 files changed

+46
-16
lines changed

lib/internal/errors.js

+6
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ function lazyBuffer() {
191191
}
192192

193193
function isErrorStackTraceLimitWritable() {
194+
// Do no touch Error.stackTraceLimit as V8 would attempt to install
195+
// it again during deserialization.
196+
if (require('v8').startupSnapshot.isBuildingSnapshot()) {
197+
return false;
198+
}
199+
194200
const desc = ObjectGetOwnPropertyDescriptor(Error, 'stackTraceLimit');
195201
if (desc === undefined) {
196202
return ObjectIsExtensible(Error);

lib/internal/main/mksnapshot.js

+32-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
const {
44
Error,
5+
ObjectDefineProperty,
6+
ObjectGetOwnPropertyDescriptor,
7+
ObjectSetPrototypeOf,
8+
SafeArrayIterator,
59
SafeSet,
6-
SafeArrayIterator
710
} = primordials;
811

912
const binding = internalBinding('mksnapshot');
@@ -125,7 +128,21 @@ function main() {
125128
const source = readFileSync(file, 'utf-8');
126129
const serializeMainFunction = compileSerializeMain(filename, source);
127130

128-
require('internal/v8/startup_snapshot').initializeCallbacks();
131+
const {
132+
initializeCallbacks,
133+
namespace: {
134+
addSerializeCallback,
135+
addDeserializeCallback,
136+
},
137+
} = require('internal/v8/startup_snapshot');
138+
initializeCallbacks();
139+
140+
let stackTraceLimitDesc;
141+
addDeserializeCallback(() => {
142+
if (stackTraceLimitDesc !== undefined) {
143+
ObjectDefineProperty(Error, 'stackTraceLimit', stackTraceLimitDesc);
144+
}
145+
});
129146

130147
if (getOptionValue('--inspect-brk')) {
131148
internalBinding('inspector').callAndPauseOnStart(
@@ -134,6 +151,19 @@ function main() {
134151
} else {
135152
serializeMainFunction(requireForUserSnapshot, filename, dirname);
136153
}
154+
155+
addSerializeCallback(() => {
156+
stackTraceLimitDesc = ObjectGetOwnPropertyDescriptor(Error, 'stackTraceLimit');
157+
158+
if (stackTraceLimitDesc !== undefined) {
159+
// We want to use null-prototype objects to not rely on globally mutable
160+
// %Object.prototype%.
161+
ObjectSetPrototypeOf(stackTraceLimitDesc, null);
162+
process._rawDebug('Deleting Error.stackTraceLimit from the snapshot. ' +
163+
'It will be re-installed after deserialization');
164+
delete Error.stackTraceLimit;
165+
}
166+
});
137167
}
138168

139169
main();

lib/internal/v8/startup_snapshot.js

-2
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ function runSerializeCallbacks() {
5454
const { 0: callback, 1: data } = serializeCallbacks.shift();
5555
callback(data);
5656
}
57-
// Remove the hooks from the snapshot.
58-
require('v8').startupSnapshot = undefined;
5957
}
6058

6159
function addSerializeCallback(callback, data) {

test/parallel/test-snapshot-api.js

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ const fixtures = require('../common/fixtures');
1010
const path = require('path');
1111
const fs = require('fs');
1212

13+
const v8 = require('v8');
14+
15+
// By default it should be false. We'll test that it's true in snapshot
16+
// building mode in the fixture.
17+
assert(!v8.startupSnapshot.isBuildingSnapshot());
18+
1319
tmpdir.refresh();
1420
const blobPath = path.join(tmpdir.path, 'snapshot.blob');
1521
const entry = fixtures.path('snapshot', 'v8-startup-snapshot-api.js');

test/parallel/test-snapshot-typescript.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,7 @@
22

33
// This tests the TypeScript compiler in the snapshot.
44

5-
const common = require('../common');
6-
7-
if (process.features.debug) {
8-
common.skip('V8 snapshot does not work with mutated globals yet: ' +
9-
'https://bugs.chromium.org/p/v8/issues/detail?id=12772');
10-
}
5+
require('../common');
116

127
const assert = require('assert');
138
const { spawnSync } = require('child_process');

test/parallel/test-snapshot-warning.js

+1-6
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@
44
// during snapshot serialization and installed again during
55
// deserialization.
66

7-
const common = require('../common');
8-
9-
if (process.features.debug) {
10-
common.skip('V8 snapshot does not work with mutated globals yet: ' +
11-
'https://bugs.chromium.org/p/v8/issues/detail?id=12772');
12-
}
7+
require('../common');
138

149
const assert = require('assert');
1510
const { spawnSync } = require('child_process');

0 commit comments

Comments
 (0)