Skip to content

src,lib: fix assert when Error.prepareStackTrace not overridden - #49212

Closed
codebytere wants to merge 1 commit into
nodejs:mainfrom
codebytere:fix-handle-no-override-preparestacktrace
Closed

src,lib: fix assert when Error.prepareStackTrace not overridden#49212
codebytere wants to merge 1 commit into
nodejs:mainfrom
codebytere:fix-handle-no-override-preparestacktrace

Conversation

@codebytere

@codebyterecodebytere commented Aug 17, 2023

Copy link
Copy Markdown
Member

Refs #23926

Fixes an issue caused when embedders choose to set up the v8::Isolate without a prepareStackTrace callback. In this event, several assert methods stop working because stack trace formatting relies on a SafeWeakMap that's only populated in the overridden prepareStackTrace callback.

Fix this by exposing override status under getEmbedderOptions and falling back to the default implementation of Error.prepareStackTrace if it's not been overridden.

@codebyterecodebytere added the embedding Issues and PRs related to embedding Node.js in another project. label Aug 17, 2023
@nodejs-github-botnodejs-github-bot added assert Issues and PRs related to the assert subsystem. c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Aug 17, 2023
@codebytere
codebytereforce-pushed the fix-handle-no-override-preparestacktrace branch from 40a5d30 to 661bc35CompareAugust 17, 2023 10:34
@codebytere
codebytereforce-pushed the fix-handle-no-override-preparestacktrace branch from 661bc35 to 151654eCompareAugust 17, 2023 10:36
Comment threadsrc/node_options.cc
FIXED_ONE_BYTE_STRING(
env->isolate(), "hasPrepareStackTraceCallback"),
Boolean::New(isolate,
!env->prepare_stack_trace_callback().IsEmpty()))

@joyeecheungjoyeecheungAug 17, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is overridden when the realm is bootstrapped though, unless SetIsolateUpForNode() is somehow called after CreateEnvironment() this would not have worked?

setPrepareStackTraceCallback(prepareStackTrace);

I wonder if this flag should've been moved into EnvironmentFlags instead (and if that's too breaking, keep SHOULD_NOT_SET_PREPARE_STACK_TRACE_CALLBACK a dummy flag there), and the GetEmbedderOptions() could query that flag stored into the Environment instead. At bootstrap time, we could just skip setPrepareStackTraceCallback if that flag is true.

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joyeecheung ah, we do call CreateEnvironment() before SetIsolateUpForNode() - I can switch that around.

Comment threadlib/assert.js
overrideStackTrace.set(err, (_, stack) => stack);
call = err.stack[0];
} else {
const tmpPrepare = Error.prepareStackTrace;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm actually I think both blocks are assuming env->prepare_stack_trace_callback() would be called here? Error.prepareStackTrace doesn't even do anything if env->prepare_stack_trace_callback() is not configured (it's a polyfill for that hook).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work: https://github.com/v8/v8/blob/main/src/execution/messages.cc#L325-L335 What we polyfill in nodejs is that Error.prepareStackTrace in the main realm will affect stack traces in any other realm.

@joyeecheungjoyeecheungAug 18, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah didn't realize that V8 has not removed it yet..in that case I wonder if instead of using the WeakMap, we can just switch to storing a v8::Private::ForApi() to the error to indicate that the prepare stack trace callback should use the function stored with that symbol to override the stack trace? Then the embedder can also communicate with the Node.js internals using v8::Private::ForApi() without requiring access to the overrideStackTrace map - overrideStackTrace isn't only used here, even, and WeakMap semantics means using v8::Private::ForApi() would just be equivalent. That would also avoid the Error.prepareStackTrace configurability/writability problem.

Comment threadlib/assert.js
call = err.stack[0];
} else {
const tmpPrepare = Error.prepareStackTrace;
Error.prepareStackTrace = (_, stack) => stack;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would throw if Error.prepareStackTrace is not writable, not sure if that's desirable.

Comment threadlib/.eslintrc.yaml Outdated
message: Use an error exported by the internal/errors module.
- selector: CallExpression[callee.object.name='Error'][callee.property.name='captureStackTrace']
message: Please use `require('internal/errors').hideStackFrames()` instead.
- selector: AssignmentExpression:matches([left.name='prepareStackTrace'], [left.property.name='prepareStackTrace'])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of removing this, you can add // eslint-disable-next-line no-restricted-syntax

Comment threadlib/assert.js
overrideStackTrace.set(err, (_, stack) => stack);
call = err.stack[0];
} else {
const tmpPrepare = Error.prepareStackTrace;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work: https://github.com/v8/v8/blob/main/src/execution/messages.cc#L325-L335 What we polyfill in nodejs is that Error.prepareStackTrace in the main realm will affect stack traces in any other realm.

@codebytere
codebytere deleted the fix-handle-no-override-preparestacktrace branch April 5, 2025 18:58
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

assertIssues and PRs related to the assert subsystem.c++Issues and PRs that require attention from people who are familiar with C++.embeddingIssues and PRs related to embedding Node.js in another project.needs-ciPRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants

@codebytere@joyeecheung@devsnek@aduh95@nodejs-github-bot