Skip to content

fs: prevent multiple invocations of callback in Dir class #58430

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

0hmX
Copy link
Contributor

@0hmX 0hmX commented May 23, 2025

Refs: #58419

I am only implementing this for the Dir class because I can create a case where it produces an error.

const fs = require('fs');

(async () => {
  const dir = await fs.promises.opendir(__dirname);
  let callCount = 0;
  // Monkey-patch the callback to throw on the first call
  function testCallback(err, dirent) {
    callCount++;
    if (callCount === 1) {
      console.log('First callback, throwing error!');
      throw new Error('Callback throws!');
    } else {
      console.log('Second callback:', err);
    }
  }
  // Call the internal read method directly (for demonstration)
  dir.read(testCallback);
})();

@nodejs-github-bot nodejs-github-bot added fs Issues and PRs related to the fs subsystem / file system. needs-ci PRs that need a full CI run. labels May 23, 2025
@0hmX 0hmX marked this pull request as ready for review May 23, 2025 04:39
Copy link

codecov bot commented May 23, 2025

Codecov Report

Attention: Patch coverage is 72.72727% with 3 lines in your changes missing coverage. Please review.

Project coverage is 90.20%. Comparing base (264cad7) to head (4a99cc2).
Report is 126 commits behind head on main.

Files with missing lines Patch % Lines
lib/internal/fs/dir.js 72.72% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #58430      +/-   ##
==========================================
+ Coverage   90.18%   90.20%   +0.02%     
==========================================
  Files         629      635       +6     
  Lines      186657   187225     +568     
  Branches    36658    36761     +103     
==========================================
+ Hits       168328   168891     +563     
+ Misses      11126    11095      -31     
- Partials     7203     7239      +36     
Files with missing lines Coverage Δ
lib/internal/fs/dir.js 94.47% <72.72%> (-0.59%) ⬇️

... and 105 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@0hmX 0hmX marked this pull request as draft May 23, 2025 09:44
@0hmX 0hmX force-pushed the callbacks-firing-twice branch 2 times, most recently from 3307cf8 to 2fdc8ee Compare May 23, 2025 09:53
@0hmX 0hmX marked this pull request as ready for review May 23, 2025 09:58
@LiviaMedeiros
Copy link
Member

I am unsure if we need to add a test for this, as this bug is not a feature. I have added a test that I was using for development. Will remove it if we do not need it.

We definitely do need a test for this: to ensure that the bug is fixed, and to ensure that it doesn't appear again after changes in the future.

@0hmX 0hmX force-pushed the callbacks-firing-twice branch from 2fdc8ee to 4a99cc2 Compare May 24, 2025 03:20
@0hmX
Copy link
Contributor Author

0hmX commented May 24, 2025

@LiviaMedeiros have added the test

Copy link
Member

@LiviaMedeiros LiviaMedeiros left a comment

Choose a reason for hiding this comment

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

Thanks for working on this! Unfortunately, it might be a bit harder to fix this issue.

Comment on lines +323 to +324
// A robust fs.Dir should catch this internally and not call this callback again.
throw new Error('Simulated user error in dir.read callback');
Copy link
Member

Choose a reason for hiding this comment

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

This is not correct: fs.Dir should not catch and suppress errors from user-provided callback, this error must bubble up.

The test shows that the simulated error disappears on its way, probably due to how FSReqCallback's oncomplete is handled on C++ side.

We might need to either investigate the cause and make errors inside oncomplete be thrown, or detach the callback call from it (e.g. using queueMicrotask).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
fs Issues and PRs related to the fs subsystem / file system. needs-ci PRs that need a full CI run.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants