-
Notifications
You must be signed in to change notification settings - Fork 30k
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
timers: prevent infinite loop when subsequent immediates are cleared #9759
Conversation
You should run |
@@ -580,13 +580,15 @@ function processImmediate() { | |||
while (immediate) { | |||
domain = immediate.domain; | |||
|
|||
if (!immediate._onImmediate) | |||
continue; |
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.
This doesn't seem correct. We should definitely always skip to the next here if there is no callback (_onImmediate
).
Would it work if you moved https://github.com/nodejs/node/pull/9759/files#diff-0a5d4868b2b9b17cf9e2c11f1bd1311eR594 above this?
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.
Not sure, but I think that would only protect against the very next immediate being cleared in the callback, and not anything else after the next one in the queue and we'd be back in an infinite loop? I'll run some tests!
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.
Yep, it seems moving those lines above the if branch has no effect, we still get stuck.
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.
@hassy Could you try re-running the tests on your machine with the following patch applied?
When I tried moving the conditional above, it ran fine locally.
diff --git a/lib/timers.js b/lib/timers.js
index 37ac317..d89a1d8 100644
--- a/lib/timers.js
+++ b/lib/timers.js
@@ -578,17 +578,18 @@ function processImmediate() {
immediateQueue.head = immediateQueue.tail = null;
while (immediate) {
+
+ if (!immediate._onImmediate) {
+ immediate = immediate._idleNext;
+ continue;
+ }
+
domain = immediate.domain;
if (domain)
domain.enter();
- if (immediate._onImmediate) {
- immediate._callback = immediate._onImmediate;
- } else {
- immediate = immediate._idleNext;
- continue;
- }
+ immediate._callback = immediate._onImmediate;
// Save next in case `clearImmediate(immediate)` is called from callback
var next = immediate._idleNext;
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.
Yep, that works (since we are moving onto the next immediate before continue
ing rather than just continuing as in the original if branch, which is what led to the infinite loop).
I think I misunderstood your first comment above and tested the wrong thing.
@sam-github The OP indicated that he tried to. |
@hassy What tests fail for you on OS X? What OS X version? (I use OS X and they pass for me with this commit.) Also, we have a handy guide for writing node core tests, once you are ready. :) |
Thanks @Fishrock123. I have added a regression test for the bug now - does that look OK? |
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.
Looking better, please run make -j4 lint
though. :)
// This test ensures that if an Immediate callback clears subsequent | ||
// immediates we don't get stuck in an infinite loop. | ||
// | ||
// Ref: https://github.com/nodejs/node/issues/9756 |
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.
This probably isn't needed, the test runner has a timeout mechanism of it's own.
If you think it is, the other file should be in /fixtures/
.
Either way, this file should probably be in /parallel/
.
setTimeout(function killProcess() { | ||
// Presume the child process is spinning at 100% CPU and won't exit | ||
childProcess.kill(); | ||
assert(false, 'Child process didn\'t exit in time'); |
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.
common.fail(message)
const childProcess = fork(path.join(__dirname, 'set-and-clear-immediates.js')); | ||
|
||
childProcess.on('close', function(code) { | ||
assert(true); |
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.
does nothing, instead, wrap the callback in common.mustCall()
.
Thanks @Fishrock123! I replaced the test with a smaller one, in the right place, and linted too. :) |
Don't think any documentation needs to be updated for this? If the fix & the test look OK now, I'll squash the commits and write a proper commit message. |
@mscdex would you mind reviewing the patch please? I think you have the final say on whether this is OK or not. :-) |
}); | ||
|
||
const i2 = setImmediate(function() { | ||
}); |
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.
Tiny nit: could you put a common.fail(<message>)
into each of these? Thanks!
// | ||
// Ref: https://github.com/nodejs/node/issues/9756 | ||
|
||
setImmediate(function() { |
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.
Could you also wrap this with common.mustCall()
? :D
@hassy I've left a few comments (including one up above regarding the conditional placement), if you could fix these up we should be good to merge, I think. |
@hassy Ping? :D |
@Fishrock123 Thanks! Didn't get a notification on GH for some reason. I'll update the PR with the fixes. |
If current immediate has no callback, move on to the next one in the queue. Fixes: nodejs#9756 PR-URL: nodejs#9759
@Fishrock123 Is it OK to |
@hassy yes, we force push all the time to update PRs. Even just Feel free to squash the commits while you are at it too. :) |
edee849
to
0db74b5
Compare
@Fishrock123 Cool, done. :-) |
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.
Looks good to me. New CI: https://ci.nodejs.org/job/node-test-pull-request/5384/
@hassy btw your git info says your name is If you would like to update it to a name you prefer more, you can update it like so: $ git config --global user.email "j.random.user@example.com"
$ git config --global user.name "J. Random User" Then $ git commit --amend --reset-author
$ git push origin head --force Otherwise, just let us know that Good to land otherwise. Sorry for the delay again. |
@Fishrock123 |
Ok cool. Thanks for the contribution! Landed in 9f6f0f7 :D |
Notable changes SEMVER-MINOR - url: - add inspect function to TupleOrigin (Safia Abdalla) #10039 - crypto: - allow adding extra certs to well-known CAs (Sam Roberts) #9139 SEMVER-PATCH - buffer: - fix single-character string filling (Anna Henningsen) #9837 - handle UCS2 .fill() properly on BE (Anna Henningsen) #9837 - url: - including base argument in originFor (joyeecheung) #10021 - improve URLSearchParams spec compliance (Timothy Gu) #9484 - http: - remove stale timeout listeners (Karl Böhlmark) #9440 - build: - fix node_g target (Daniel Bevenius) #10153 - fs: - remove unused argument from copyObject() (Ethan Arrowood) #10041 - timers: - fix handling of cleared immediates (hveldstra) #9759 PR-URL: #10277
Notable changes: * **crypto**: - Allow adding extra certificates to well-known CAs. (Sam Roberts) [#9139](#9139) * **buffer**: - Fix single-character string filling. (Anna Henningsen) [#9837](#9837) - Handle UCS2 `.fill()` properly on BE. (Anna Henningsen) [#9837](#9837) * **url**: - Add inspect function to TupleOrigin. (Safia Abdalla) [#10039](#10039) - Including base argument in originFor. (joyeecheung) [#10021](#10021) - Improve URLSearchParams spec compliance. (Timothy Gu) [#9484](#9484) * **http**: - Remove stale timeout listeners. (Karl Böhlmark) [#9440](#9440) * **build**: - Fix node_g target. (Daniel Bevenius) [#10153](#10153) * **fs**: - Remove unused argument from copyObject(). (EthanArrowood) [#10041](#10041) * **timers**: - Fix handling of cleared immediates. (hveldstra) [#9759](#9759) * **src**: - Add wrapper for process.emitWarning(). (SamRoberts) [#9139](#9139) - Fix string format mistake for 32 bit node.(Alex Newman) [#10082](#10082)
PR to go with: #9756
I am not familiar with timers, so the proposed solution could well be wrong. Looking forward to feedback on that!
Checklist
make -j8 test
(UNIX), orvcbuild test nosign
(Windows) passesAffected core subsystem(s)
timers
Description of change
Remove the unnecessary
if
branch.If current
immediate
has no callback, proceed onto the next one in the queue.