-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
fix: avoid call stack overflow while processing globs #19035
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
fix: avoid call stack overflow while processing globs #19035
Conversation
✅ Deploy Preview for docs-eslint canceled.
|
488136e
to
72bf938
Compare
Would it fix the problem, and would the performance be better if we just do |
Do you mean checking non- |
I was thinking about something like this: - return filePaths;
+ return results.flatMap(result => result.value); And then we could remove the |
Like this? It looks cleaner and wouldn't be significantly slower, but we effectively iterate over |
I think that isn't a concern as |
I can reproduce the error locally: I changed
So, marking as accepted. I can confirm that the changes from this PR fix the "Maximum call stack size exceeded" problem in my test setup. Though, the test eventually fails with an |
Speaking of eslint/tools/check-emfile-handling.js Lines 43 to 46 in 50f03a1
EMFILE still occurs at least after exceeding hard limit), perhaps it should be done in scope of this PR.
|
Ah okay, it fails with |
38a50fb
to
df082d6
Compare
Yeah, it's quite possible that the comment refers to this particular call stack error. I'm not sure if it's possible to determine the max number of elements that can be spread into a function call, to ensure we'll not use spread arguments with the list of files anywhere, and then test with that number. And it seems that the test would eventually run into either an EMFILE error or a heap out of memory error. So, I'm inclined to merging this without any particular tests and consider increasing limits in the EMFILE check in a PR that will fix #18977. @nzakas what do you think? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks! Leaving it open for a second review, and since there's an open question about whether we want to add some tests in this PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know that we can determine the max number of spread arguments a function may have. I'm guessing it's close to the max number of array elements (2^32 - 1), so I hope we wont' have to worry about it.
I think it's okay to merge without a test because I'm not sure we'd be able to make a non-flaky test to validate this change. We should put a comment in the code, though, explaining what's happening so we don't accidentally change this back in the future.
@@ -421,20 +421,12 @@ async function globMultiSearch({ searches, configLoader, errorOnUnmatchedPattern | |||
) | |||
); | |||
|
|||
const filePaths = []; | |||
|
|||
for (let i = 0; i < results.length; i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add a comment here explaining what we're looping over results
twice? Especially without a test to validate this change, having some comments here would be very helpful for long-term maintenance.
Determining the real stack limit here is quite simple: we can just run something like I think the If we want to test specifically for spread operator issue and similar stuff ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks!
I'm okay merging without a test, but would like @mdjermanovic to confirm. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks! We can evaluate adding tests separately.
Prerequisites checklist
What is the purpose of this pull request? (put an "X" next to an item)
[ ] Documentation update
[x] Bug fix (template)
[ ] New rule (template)
[ ] Changes an existing rule (template)
[ ] Add autofix to a rule
[ ] Add a CLI option
[ ] Add something to the core
[ ] Other, please explain:
What changes did you make? (Give an overview)
If there's a directory with considerable amount of files (I encountered it at 150_000), pushing them at once exceeds call stack limit.
Array.prototype.push.apply(filePaths, result.value);
without spread operator would fail as well.Is there anything you'd like reviewers to focus on?
Performance.
I've tried different
CHUNK_SIZE
s between 512 and 10000, and the time curve wasn't even weakly monotonic.A good alternative would be pre-allocating the array, something like this:
But the performance benefit is negligible and IMHO it looks uglier.