Infinite loop in timers.js
- Version: 6.8.1 and later
- Platform: tested on OSX & Linux, probably all platforms
- Subsystem: timers
v6.8.1 and above will all hang when the following code is run:
var i1 = setImmediate(function() { console.log('i1 cb'); clearImmediate(i2); clearImmediate(i3); }); var i2 = setImmediate(function() { console.log('i2 cb'); }); var i3 = setImmediate(function() { console.log('i3 cb'); }); console.log('All set');
An example run of the code above:
hassy@mdb $ node -v
v4.3.2
hassy@mdb $ node isolated.js
All set
i1 cb
#
# The process exits immediately.
#
hassy@mdb $ nvm use 6.8.1
hassy@mdb $ node -v
v6.8.1
hassy@mdb $ node isolated.js
All set
i1 cb
#
# The process won't exit. top shows it using 98%+ CPU.
#
The cause is Node entering into an infinite loop here when immediate._onImmediate is null:
(source: https://github.com/nodejs/node/blob/master/lib/timers.js#L580-L587)
while (immediate) { domain = immediate.domain; if (!immediate._onImmediate) continue;
This happens when the immediate referred to by next gets cleared.
The issue first manifests itself in this commit: 42158a0
The if branch that causes an infinite loop was first introduced in
| while (L.isEmpty(queue) === false) { | |
| immediate = L.shift(queue); | |
| domain = immediate.domain; | |
| if (!immediate._onImmediate) | |
| continue; |
but is obsolete now since the value of immediate will not change once the condition is hit.
I'll send a PR to go along with this with a proposed fix.
EDIT 1: Simplified the test case.