node icon indicating copy to clipboard operation
node copied to clipboard

`Error.stackTraceLimit` becomes `undefined` when running from snapshot

Open acutmore opened this issue 5 months ago • 3 comments

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.

acutmore avatar Sep 24 '24 13:09 acutmore