readline: fix close event of readline.Interface()
authorYazhong Liu <yorkiefixer@gmail.com>
Wed, 7 May 2014 16:05:39 +0000 (00:05 +0800)
committerTrevor Norris <trev.norris@gmail.com>
Mon, 12 May 2014 21:13:14 +0000 (14:13 -0700)
Not removing 'end' listeners for input and output on the 'close' event
resulted in an EventEmitter related memory leak.

This issue also might be reproduced at:
https://github.com/npm/npm/issues/5203

Signed-off-by: Trevor Norris <trev.norris@gmail.com>
lib/readline.js
test/simple/test-readline-interface.js

index 1fa217c..19ef759 100644 (file)
@@ -97,6 +97,13 @@ function Interface(input, output, completer, terminal) {
     self.close();
   }
 
+  function ontermend() {
+    if (util.isString(self.line) && self.line.length > 0) {
+      self.emit('line', self.line);
+    }
+    self.close();
+  }
+
   function onkeypress(s, key) {
     self._ttyWrite(s, key);
   }
@@ -121,11 +128,7 @@ function Interface(input, output, completer, terminal) {
 
     // input usually refers to stdin
     input.on('keypress', onkeypress);
-    input.on('end', function inputEnd() {
-      if (util.isString(self.line) && self.line.length > 0)
-        self.emit('line', self.line);
-      self.close();
-    });
+    input.on('end', ontermend);
 
     // Current line
     this.line = '';
@@ -142,6 +145,7 @@ function Interface(input, output, completer, terminal) {
     output.on('resize', onresize);
     self.once('close', function() {
       input.removeListener('keypress', onkeypress);
+      input.removeListener('end', ontermend);
       output.removeListener('resize', onresize);
     });
   }
index 930cf22..abd3681 100644 (file)
@@ -35,6 +35,14 @@ FakeInput.prototype.pause = function() {};
 FakeInput.prototype.write = function() {};
 FakeInput.prototype.end = function() {};
 
+function isWarned(emitter) {
+  for (var name in emitter) {
+    var listeners = emitter[name];
+    if (listeners.warned) return true;
+  }
+  return false;
+}
+
 [ true, false ].forEach(function(terminal) {
   var fi;
   var rli;
@@ -262,4 +270,17 @@ FakeInput.prototype.end = function() {};
   assert.equal(readline.getStringWidth('> '), 2);
 
   assert.deepEqual(fi.listeners(terminal ? 'keypress' : 'data'), []);
+
+  // check EventEmitter memory leak
+  for (var i=0; i<12; i++) {
+    var rl = readline.createInterface({
+      input: process.stdin,
+      output: process.stdout
+    });
+    rl.close();
+    assert.equal(isWarned(process.stdin._events), false);
+    assert.equal(isWarned(process.stdout._events), false);
+  }
+
 });
+