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

segfault if clearTimeout(interval) #9561

Closed
watson opened this issue Nov 12, 2016 · 10 comments · Fixed by #9685
Closed

segfault if clearTimeout(interval) #9561

watson opened this issue Nov 12, 2016 · 10 comments · Fixed by #9685
Assignees
Labels
confirmed-bug Issues with confirmed bugs. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout.

Comments

@watson
Copy link
Member

watson commented Nov 12, 2016

  • Version: v6.9.1
  • Platform: Darwin watson-3.local 16.1.0 Darwin Kernel Version 16.1.0: Thu Oct 13 21:26:57 PDT 2016; root:xnu-3789.21.3~60/RELEASE_X86_64 x86_64
  • Subsystem:

If using clearTimeout to clear an unreffed Timeout object returned by setInterval(...).unref() you'll get a segfault the next time the interval would normally have fired.

The following example program will segfault after 4 seconds:

// keep the event loop busy while we wait for segfault
setTimeout(function () {}, 100000)

console.log('setInterval')
var timer = setInterval(clear, 2000).unref()

function clear () {
  console.log('clear - start')

  // Use clearTimeout instead of clearInterval
  clearTimeout(timer)

  console.log('clear - end')
}

The segfault doesn't happen if the Timeout object isn't unreffed.

Even though the user should just use clearInterval instead, this at least shouldn't segfault.

@mscdex mscdex added c++ Issues and PRs that require attention from people who are familiar with C++. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout. and removed c++ Issues and PRs that require attention from people who are familiar with C++. labels Nov 12, 2016
@Fishrock123 Fishrock123 self-assigned this Nov 12, 2016
@Fishrock123 Fishrock123 added the confirmed-bug Issues with confirmed bugs. label Nov 12, 2016
@bnoordhuis
Copy link
Member

bnoordhuis commented Nov 14, 2016

I did a quick bisect to see if it's a regression. I didn't find a culprit but it seems to go back to July at least.

EDIT: Worth noting that the crash seems to be caused by a wrap->object() in OnTimeout() that is a tagged integer, not a JS heap object.

@Fishrock123
Copy link
Contributor

Worth noting that the crash seems to be caused by a wrap->object() in OnTimeout() that is a tagged integer, not a JS heap object.

Are you sure about that? The unsigned integer should be the property name, which it appears to be?

@Fishrock123
Copy link
Contributor

Ok, I think rearm() is just not properly checking if the timer was unenrolled.

@Fishrock123
Copy link
Contributor

Fishrock123 commented Nov 14, 2016

Not enough care was given in the recent interval refactor and several related bugs also exist. The following do not work correctly inside an Interval callback:

  • clearTimeout(timer)
  • Timer#close()
  • unenroll(timer)
  • timer._onTimeout = null
  • timer._idleTimeout = -1

Edit: Some of these may have existed before the refactor, so it is probably not entirely to blame.

@MylesBorins
Copy link
Contributor

@Fishrock123 can you link to the PR of the interval refactor please

@Fishrock123
Copy link
Contributor

@thealphanerd sorry, was short on time earlier.

Commit: c8c2544
Pull request: #8661

@Fishrock123
Copy link
Contributor

Fishrock123 commented Nov 14, 2016

This is in part due to the fault of clarity in the timers codebase that _idleTimeout === -1 is the closest to an authoritative way to tell if a timer is canceled, but that isn't 100% maintained in every possible cancel path. (I will probably fix some of this at the same time.)

@Fishrock123
Copy link
Contributor

Hmmm, actually fixing this correctly is proving a bit of a challenge, there are some odd cases with Timeout#close() when unrefed.

@Fishrock123
Copy link
Contributor

Still on this, will try to fix tomorrow or next week.

Fishrock123 added a commit to Fishrock123/node that referenced this issue Nov 22, 2016
Previously not all codepaths set `timer._idleTimeout = -1` for canceled
or closed timers, and not all codepaths checked it either.

Unenroll uses this to say that a timer is indeed closed and it is the
closest thing there is to an authoritative source for this.

Refs: nodejs#9606
Fixes: nodejs#9561
PR-URL: nodejs#9685
Reviewed-By: Rich Trott <rtrott@gmail.com>
Fishrock123 added a commit that referenced this issue Nov 22, 2016
Previously not all codepaths set `timer._idleTimeout = -1` for canceled
or closed timers, and not all codepaths checked it either.

Unenroll uses this to say that a timer is indeed closed and it is the
closest thing there is to an authoritative source for this.

Refs: #9606
Fixes: #9561
PR-URL: #9685
Reviewed-By: Rich Trott <rtrott@gmail.com>
@jucrouzet
Copy link

If it can help, also crashes on Node 4.4.2 with a more verbose message :
node: ../src/timer_wrap.cc:74: static void node::TimerWrap::Start(const v8::FunctionCallbackInfo<v8::Value>&): Assertion HandleWrap::IsAlive(wrap)' failed.`

Fishrock123 added a commit to Fishrock123/node that referenced this issue Dec 21, 2016
Previously not all codepaths set `timer._idleTimeout = -1` for canceled
or closed timers, and not all codepaths checked it either.

Unenroll uses this to say that a timer is indeed closed and it is the
closest thing there is to an authoritative source for this.

Refs: nodejs#9606
Fixes: nodejs#9561
PR-URL: nodejs#9685
Reviewed-By: Rich Trott <rtrott@gmail.com>

 Conflicts:
	lib/timers.js
MylesBorins pushed a commit that referenced this issue Dec 21, 2016
Previously not all codepaths set `timer._idleTimeout = -1` for canceled
or closed timers, and not all codepaths checked it either.

Unenroll uses this to say that a timer is indeed closed and it is the
closest thing there is to an authoritative source for this.

Refs: #9606
Fixes: #9561
PR-URL: #9685
Reviewed-By: Rich Trott <rtrott@gmail.com>

 Conflicts:
	lib/timers.js
MylesBorins pushed a commit that referenced this issue Dec 21, 2016
Previously not all codepaths set `timer._idleTimeout = -1` for canceled
or closed timers, and not all codepaths checked it either.

Unenroll uses this to say that a timer is indeed closed and it is the
closest thing there is to an authoritative source for this.

Refs: #9606
Fixes: #9561
PR-URL: #9685
Reviewed-By: Rich Trott <rtrott@gmail.com>
MylesBorins pushed a commit that referenced this issue Dec 21, 2016
Previously not all codepaths set `timer._idleTimeout = -1` for canceled
or closed timers, and not all codepaths checked it either.

Unenroll uses this to say that a timer is indeed closed and it is the
closest thing there is to an authoritative source for this.

Refs: #9606
Fixes: #9561
PR-URL: #9685
Reviewed-By: Rich Trott <rtrott@gmail.com>
MylesBorins pushed a commit that referenced this issue Dec 21, 2016
Previously not all codepaths set `timer._idleTimeout = -1` for canceled
or closed timers, and not all codepaths checked it either.

Unenroll uses this to say that a timer is indeed closed and it is the
closest thing there is to an authoritative source for this.

Refs: #9606
Fixes: #9561
PR-URL: #9685
Reviewed-By: Rich Trott <rtrott@gmail.com>

 Conflicts:
	lib/timers.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
confirmed-bug Issues with confirmed bugs. timers Issues and PRs related to the timers subsystem / setImmediate, setInterval, setTimeout.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants