node
node copied to clipboard
`Error.stackTraceLimit` becomes `undefined` when running from snapshot
Version
v22.8.0
Platform
Darwin KGVY6KLQ1J 23.6.0 Darwin Kernel Version 23.6.0: Mon Jul 29 21:13:04 PDT 2024; root:xnu-10063.141.2~1/RELEASE_ARM64_T6020 arm64
Subsystem
No response
What steps will reproduce the bug?
Description
Error.stackTraceLimit
is undefined
while the snapshot is being run, meaning code which "resets" stackTraceLimit
after temporarily modifying it is consequently setting it to undefined
which is persisted when resuming from the snapshot.
I hit this when importing typescript
while building the snapshot.
Setup
Create this file:
// app.js
function warmup() {
// simplified version of https://github.com/microsoft/TypeScript/blob/fa0080f4802fd78fb0f01cd0160f299794d7843d/src/compiler/sys.ts#L1897-L1919
const previousLimit = Error.stackTraceLimit;
try {
Error.stackTraceLimit = 1;
// ...do stuff
} finally {
Error.stackTraceLimit = previousLimit;
console.log("warmup: Error.stackTraceLimit is ", Error.stackTraceLimit);
}
}
function task() {
const err = new Error();
console.log("task: typeof err.stack is ", typeof err.stack);
}
const v8 = require("v8");
if (v8.startupSnapshot.isBuildingSnapshot()) {
warmup();
v8.startupSnapshot.setDeserializeMainFunction(task);
} else {
warmup();
task();
}
No snapshots:
> node app.js
warmup: Error.stackTraceLimit is 10
task: typeof err.stack is string
With snapshots:
> node --snapshot-blob=snap.blob --build-snapshot app.js
warmup: Error.stackTraceLimit is undefined
Deleting Error.stackTraceLimit from the snapshot. It will be re-installed after deserialization
> node -snapshot-blob=snap.blob app.js
task: typeof err.stack is undefined
How often does it reproduce? Is there a required condition?
100%
What is the expected behavior? Why is that the expected behavior?
I was expecting Error.stackTraceLimit
to have the same starting value regardless of if --build-snapshot
is passed.
As a result I was also expecting error.stack
within task
to be defined when running from the snapshot, because it is defined when running without the snapshot.
What do you see instead?
Error.stackTraceLimit
is undefined
when running with --build-snapshot
.
As a result typeof error.stack
is string
when running the code normally and undefined
when using a snapshot.
Additional information
Startup snapshots parent issue: #44014
error.stack
being undefined
while building the snapshot - I presume this is there as a security precaution to avoid leaking implementation details of the file system into the snapshot? Maybe this could be documented? (apologies if this is already the case)
I wonder if the logic for restoring Error.stackTraceLimit
should only happen if the snapshot builder explicitly sets Error.stackTraceLimit
to a number and not to undefined
- because undefined
is the starting state it hasn't actually been changed by the snapshot builder.
The workaround I have in place is to explicitly set Error.stackTraceLimit = 10;
before exiting the snapshot builder. This works, however it would be nice to not hard-code the size and instead allow it to retain the default. EDIT: delete Error.stackTraceLimit;
at the end of the snapshot building seems to be a 'better' workaround.