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

module: prevent main thread exiting before esm worker ends #56183

Merged
merged 2 commits into from
Dec 10, 2024

Conversation

islandryu
Copy link
Contributor

This fix ensures the main thread does not terminate before an ESM worker's handleMessage function completes by moving the atomic lock release to the end of the function. As far as I can see, there doesn’t seem to be any necessary processing after the lock release.

Problem

The test-esm-loader-spawn-promisified.mjs test occasionally fails in debug builds. If processing after the lock release exceeds the stack limit, it results in a fatal error:

✖ can predetermine the format in the custom loader resolve hook (162.586375ms)
  AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
  + actual - expected
  
  + '\n' +
  +   '\n' +
  +   '#\n' +
  +   '# Fatal error in ../../deps/v8/src/api/api.cc, line 5021\n' +
  +   '# Debug check failed: !i_isolate->is_execution_terminating().\n' +
... 

Even if it fails in a debug build, it is desirable for the error to be a JavaScript error, such as Maximum call stack size exceeded, rather than a debug check error.

Although it involves modifying the internal code, the issue can be reproduced as follows:

// Insert code that intentionally exceeds the stack limit at line 220 of lib/internal/modules/esm/worker.js before the fix.
    if(method === "load" && args[0].includes("imported.mjs")) {
      function func() {
          func();
      }
      func();
    } 

// index.mjs
await import("./imported.mjs")
console.log("done")

// run index.mjs with any loader and any imported.mjs

Test

Testing this precisely is difficult due to timing sensitivity. A new test verifies that a deliberate stack overflow results in the correct Maximum call stack size exceeded error, ensuring the lock behavior is correct.

@nodejs-github-bot
Copy link
Collaborator

Review requested:

  • @nodejs/loaders

@nodejs-github-bot nodejs-github-bot added esm Issues and PRs related to the ECMAScript Modules implementation. needs-ci PRs that need a full CI run. labels Dec 8, 2024
Copy link

codecov bot commented Dec 8, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.49%. Comparing base (ac7fea6) to head (b0c0ece).
Report is 25 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #56183      +/-   ##
==========================================
+ Coverage   88.01%   88.49%   +0.48%     
==========================================
  Files         656      656              
  Lines      189136   189263     +127     
  Branches    36004    36348     +344     
==========================================
+ Hits       166461   167497    +1036     
+ Misses      15842    14977     -865     
+ Partials     6833     6789      -44     
Files with missing lines Coverage Δ
lib/internal/modules/esm/worker.js 91.35% <100.00%> (+0.06%) ⬆️

... and 101 files with indirect coverage changes

Copy link
Member

@mcollina mcollina 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 nit

lib/internal/modules/esm/worker.js Outdated Show resolved Hide resolved
@aduh95 aduh95 added author ready PRs that have at least one approval, no pending requests for changes, and a CI started. request-ci Add this label to start a Jenkins CI on a PR. lts-watch-v18.x PRs that may need to be released in v18.x. lts-watch-v20.x PRs that may need to be released in v20.x labels Dec 8, 2024
@github-actions github-actions bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Dec 8, 2024
@nodejs-github-bot
Copy link
Collaborator

@nodejs-github-bot
Copy link
Collaborator

@JakobJingleheimer
Copy link
Member

Sorry I'm swamped this week.

This sounds like something we tried back when that led to a deadlock in some circumstances. I was going to ask Antoine, who I think worked on that specific scenario with me; I see he has reviewed this though.

Copy link
Member

@JakobJingleheimer JakobJingleheimer left a comment

Choose a reason for hiding this comment

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

I can't think of the specific issue; we surely would have added a test-case for it before landing, so if the tests are passing, it should be okay!

Thanks for this!

Does this also address console.logs getting "lost"? If so, the API docs should to be updated to remove the caveat. I think that should happen in this PR for an atomic change.

@aduh95 aduh95 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 10, 2024
@nodejs-github-bot nodejs-github-bot removed the commit-queue Add this label to land a pull request using GitHub Actions. label Dec 10, 2024
@nodejs-github-bot nodejs-github-bot merged commit 2063245 into nodejs:main Dec 10, 2024
76 checks passed
@nodejs-github-bot
Copy link
Collaborator

Landed in 2063245

@islandryu
Copy link
Contributor Author

@JakobJingleheimer

Sorry for the delayed response.
Regarding "console.logs getting lost," are you referring to this part?
https://nodejs.org/api/module.html#hooks

Hooks are run in a separate thread, isolated from the main thread where application code runs. That means it is a different realm. The hooks thread may be terminated by the main thread at any time, so do not depend on asynchronous operations (like console.log) to complete.

I made the change to lock the main thread until handleMessage completes, but I overlooked asynchronous considerations.
There might still be a possibility of logs getting lost in the sections executed after handleMessage.

targos pushed a commit that referenced this pull request Dec 13, 2024
PR-URL: #56183
Reviewed-By: Matteo Collina <[email protected]>
Reviewed-By: Antoine du Hamel <[email protected]>
Reviewed-By: Jacob Smith <[email protected]>
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. commit-queue-squash Add this label to instruct the Commit Queue to squash all the PR commits into the first one. esm Issues and PRs related to the ECMAScript Modules implementation. lts-watch-v18.x PRs that may need to be released in v18.x. lts-watch-v20.x PRs that may need to be released in v20.x needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants