timers: do not restart the interval after close
authorFedor Indutny <fedor@indutny.com>
Thu, 2 Apr 2015 22:14:08 +0000 (01:14 +0300)
committerFedor Indutny <fedor@indutny.com>
Fri, 3 Apr 2015 23:31:47 +0000 (02:31 +0300)
Partially revert 776b73b24306bac0ce299df4f90b7645d5efca31.

Following code crashes after backported timer leak fixes:

```javascript
var timer = setInterval(function() {
  clearInterval(timer);
}, 10);
timer.unref();
```

Note that this is actually tested in a `test-timers-unref.js`, and is
crashing only with 776b73b24306bac0ce299df4f90b7645d5efca31.

Calling `clearInterval` leads to the crashes in case of `.unref()`ed
timers, and might lead to a extra timer spin in case of regular
intervals that was closed during the interval callback. All of these
happens because `.unref()`ed timer has it's own `_handle` and was used
after the `.close()`.

PR-URL: https://github.com/iojs/io.js/pull/1330
Reviewed-by: Trevor Norris <trev.norris@gmail.com>
lib/timers.js
src/timer_wrap.cc

index 4427894..dea1013 100644 (file)
@@ -272,6 +272,11 @@ exports.setInterval = function(callback, repeat) {
 
   function wrapper() {
     timer._repeat.call(this);
+
+    // Timer might be closed - no point in restarting it
+    if (!timer._repeat)
+      return;
+
     // If timer is unref'd (or was - it's permanently removed from the list.)
     if (this._handle) {
       this._handle.start(repeat, 0);
index d71213f..f65290a 100644 (file)
@@ -73,6 +73,8 @@ class TimerWrap : public HandleWrap {
   static void Start(const FunctionCallbackInfo<Value>& args) {
     TimerWrap* wrap = Unwrap<TimerWrap>(args.Holder());
 
+    CHECK(HandleWrap::IsAlive(wrap));
+
     int64_t timeout = args[0]->IntegerValue();
     int64_t repeat = args[1]->IntegerValue();
     int err = uv_timer_start(&wrap->handle_, OnTimeout, timeout, repeat);
@@ -82,6 +84,8 @@ class TimerWrap : public HandleWrap {
   static void Stop(const FunctionCallbackInfo<Value>& args) {
     TimerWrap* wrap = Unwrap<TimerWrap>(args.Holder());
 
+    CHECK(HandleWrap::IsAlive(wrap));
+
     int err = uv_timer_stop(&wrap->handle_);
     args.GetReturnValue().Set(err);
   }
@@ -89,6 +93,8 @@ class TimerWrap : public HandleWrap {
   static void Again(const FunctionCallbackInfo<Value>& args) {
     TimerWrap* wrap = Unwrap<TimerWrap>(args.Holder());
 
+    CHECK(HandleWrap::IsAlive(wrap));
+
     int err = uv_timer_again(&wrap->handle_);
     args.GetReturnValue().Set(err);
   }
@@ -96,6 +102,8 @@ class TimerWrap : public HandleWrap {
   static void SetRepeat(const FunctionCallbackInfo<Value>& args) {
     TimerWrap* wrap = Unwrap<TimerWrap>(args.Holder());
 
+    CHECK(HandleWrap::IsAlive(wrap));
+
     int64_t repeat = args[0]->IntegerValue();
     uv_timer_set_repeat(&wrap->handle_, repeat);
     args.GetReturnValue().Set(0);
@@ -104,6 +112,8 @@ class TimerWrap : public HandleWrap {
   static void GetRepeat(const FunctionCallbackInfo<Value>& args) {
     TimerWrap* wrap = Unwrap<TimerWrap>(args.Holder());
 
+    CHECK(HandleWrap::IsAlive(wrap));
+
     int64_t repeat = uv_timer_get_repeat(&wrap->handle_);
     if (repeat <= 0xfffffff)
       args.GetReturnValue().Set(static_cast<uint32_t>(repeat));