Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: fix backtrace with [[noreturn]] abort #50849

Merged
merged 4 commits into from
Dec 3, 2023

Conversation

legendecas
Copy link
Member

@legendecas legendecas commented Nov 22, 2023

A function calls [[noreturn]] node::Abort will print an incorrect
call stack because the frame pc was advanced to an invalid op
when calling node::Abort, which may vary on different platforms.

Dumps the backtrace in the ABORT macro instead to avoid calling
backtrace in a [[noreturn]] call. Removes the [[noreturn]]
attribute if a function calls backtrace.

[[noreturn]] attribute of public functions like napi_fatal_error and
node::OnFatalError can not be removed as compilers may complain
about no return values after the removal.

Refs: #50761

A function tail calls [[noreturn]] node::Abort will print an incorrect
call stack because the frame pc was advanced when calling node::Abort
to an invalid op, which may vary on different platforms.

Dumps the backtrace in the ABORT macro instead to avoid calling
backtrace in a tail [[noreturn]] call. Removes the [[noreturn]]
attribute if a function calls backtrace and may be called as a tail
statement.

[[noreturn]] attribute of public functions like `napi_fatal_error` and
`node::OnFatalError` can not be removed as compilers may complain
about no return values after the removal.
@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. labels Nov 22, 2023
src/node_errors.h Outdated Show resolved Hide resolved
src/util.h Show resolved Hide resolved
src/util.h Outdated Show resolved Hide resolved
src/node_errors.h Show resolved Hide resolved
src/node_errors.cc Show resolved Hide resolved
@joyeecheung
Copy link
Member

joyeecheung commented Nov 23, 2023

By the way does it matter if abort is tail called or not? I think as long as the caller is marked as [[noreturn]], the compiler is completely free to just not maintain the frame pointer/link register for backtrace (it seems LLVM is particularly eager to do this which I guess is why we are seeing this showing up more on macOS). So the rule of thumb here is to just not mark [[noreturn]] for any caller of backtrace().

@legendecas legendecas changed the title src: fix backtrace with tail [[noreturn]] abort src: fix backtrace with [[noreturn]] abort Nov 23, 2023
@legendecas
Copy link
Member Author

legendecas commented Nov 23, 2023

By the way does it matter if abort is tail called or not? I think as long as the caller is marked as [[noreturn]], the compiler is completely free to just not maintain the frame pointer/link register for backtrace (it seems LLVM is particularly eager to do this which I guess is why we are seeing this showing up more on macOS). So the rule of thumb here is to just not mark [[noreturn]] for any caller of backtrace().

I checked different call sites and their generated code, and I found that a tail call to [[noreturn]] is more eager to be optimized. For example, the following snippet would print the correct backtrace when it reaches the abort:

MaybeLocal<String> BuiltinLoader::LoadBuiltinSource(Isolate* isolate,
                                                    const char* id) const {
  auto source = source_.read();
  const auto source_it = source->find(id);
  if (UNLIKELY(source_it == source->end())) {
    fprintf(stderr, "Cannot find native builtin: \"%s\".\n", id);
    node::Abort();
  }
  return source_it->second.ToStringChecked(isolate);
}

But, yes, the rule should be that we should not mark functions as [[noreturn]] for callers of backtrace().

@joyeecheung
Copy link
Member

@legendecas Do you have time to address the comments? test-worker-nearheaplimit-deadlock has been haunting the CI for some time, so I'd like to see this landed soon-ish to get some more information out of the flakes.

Copy link
Member

@joyeecheung joyeecheung left a comment

Choose a reason for hiding this comment

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

LGTM with a suggestion to comments

src/util.h Outdated Show resolved Hide resolved
@joyeecheung joyeecheung added the request-ci Add this label to start a Jenkins CI on a PR. label Nov 28, 2023
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Nov 28, 2023
@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@legendecas legendecas added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Nov 29, 2023
@joyeecheung joyeecheung added commit-queue Add this label to land a pull request using GitHub Actions. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. labels Dec 3, 2023
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Dec 3, 2023
@nodejs-github-bot nodejs-github-bot merged commit 16a5479 into nodejs:main Dec 3, 2023
59 checks passed
@nodejs-github-bot
Copy link
Collaborator

Landed in 16a5479

@legendecas legendecas deleted the backtrace-noreturn branch December 3, 2023 17:47
targos pushed a commit that referenced this pull request Dec 4, 2023
A function tail calls [[noreturn]] node::Abort will print an incorrect
call stack because the frame pc was advanced when calling node::Abort
to an invalid op, which may vary on different platforms.

Dumps the backtrace in the ABORT macro instead to avoid calling
backtrace in a tail [[noreturn]] call. Removes the [[noreturn]]
attribute if a function calls backtrace and may be called as a tail
statement.

[[noreturn]] attribute of public functions like `napi_fatal_error` and
`node::OnFatalError` can not be removed as compilers may complain
about no return values after the removal.

PR-URL: #50849
Refs: #50761
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
@targos targos mentioned this pull request Dec 4, 2023
richardlau pushed a commit that referenced this pull request Mar 25, 2024
A function tail calls [[noreturn]] node::Abort will print an incorrect
call stack because the frame pc was advanced when calling node::Abort
to an invalid op, which may vary on different platforms.

Dumps the backtrace in the ABORT macro instead to avoid calling
backtrace in a tail [[noreturn]] call. Removes the [[noreturn]]
attribute if a function calls backtrace and may be called as a tail
statement.

[[noreturn]] attribute of public functions like `napi_fatal_error` and
`node::OnFatalError` can not be removed as compilers may complain
about no return values after the removal.

PR-URL: #50849
Refs: #50761
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
@richardlau richardlau mentioned this pull request Mar 25, 2024
@joyeecheung
Copy link
Member

Actually I noticed in https://ci.nodejs.org/job/node-test-binary-windows-js-suites/26795/RUN_SUBSET=1,nodes=win2022-COMPILED_BY-vs2022/console that this change is breaking most of the places being converted to use ABORT() without marking themselves as [[noreturn]]. I think the original point about not making [[noreturn]] Abort() should be revisited:

int MyFunction(int value) {
  if (value >= 0) {
    return value;
  }
  // if Abort is not marked as [[noreturn]], compiler 
  // will complain about no return value in this branch.
  Abort();
};

In this case the function should be rewritten like this:

int MyFunction(int value) {
  if (value < 0) {
    Abort();
  }
  return value;
};

Otherwise every caller of the ABORT() macro has to be marked as [[noreturn]] and the chain is infectious, which is probably not practical.

@joyeecheung
Copy link
Member

Oh wait, I think I got it the other way around. Callers of ABORT() must not be macro. Though it seems with msvc, the macro is causing some problems to properly backtrace..

@legendecas
Copy link
Member Author

@joyeecheung sorry, but the link you provided didn't report a compiler error. Is the link correct?

@joyeecheung
Copy link
Member

The issue is in the crashed test-buffer-isascii with incorrect native stack traces, what we originally tried to fix

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. c++ Issues and PRs that require attention from people who are familiar with C++. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants