From 2c84c946bed09391b6006c12f3bfc84b532b339b Mon Sep 17 00:00:00 2001 From: Alex Kocharin Date: Sun, 5 Jul 2015 19:16:47 +0300 Subject: [PATCH] readline: fix freeze if `keypress` event throws `emitKeys` is a generator which emits `keypress` events in an infinite loop. But if `keypress` event handler throws, the error stops the loop, leaving generator in a broken state. So this patch restarts the generator when an error occures. --- lib/readline.js | 10 +++++++++- test/parallel/test-readline-interface.js | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/lib/readline.js b/lib/readline.js index d186eef94ae328..741f58b934b688 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -910,7 +910,15 @@ function emitKeypressEvents(stream) { var r = stream[KEYPRESS_DECODER].write(b); if (r) { for (var i = 0; i < r.length; i++) { - stream[ESCAPE_DECODER].next(r[i]); + try { + stream[ESCAPE_DECODER].next(r[i]); + } catch (err) { + // if the generator throws (it could happen in the `keypress` + // event), we need to restart it. + stream[ESCAPE_DECODER] = emitKeys(stream); + stream[ESCAPE_DECODER].next(); + throw err; + } } } } else { diff --git a/test/parallel/test-readline-interface.js b/test/parallel/test-readline-interface.js index 6ee9ad227896b1..e11cfd333b9dfb 100644 --- a/test/parallel/test-readline-interface.js +++ b/test/parallel/test-readline-interface.js @@ -192,6 +192,24 @@ function isWarned(emitter) { assert.equal(callCount, 1); rli.close(); + // Regression test for repl freeze, #1968: + // check that nothing fails if 'keypress' event throws. + fi = new FakeInput(); + rli = new readline.Interface({ input: fi, output: fi, terminal: true }); + var keys = []; + fi.on('keypress', function(key) { + keys.push(key); + if (key === 'X') { + throw new Error('bad thing happened'); + } + }); + try { + fi.emit('data', 'fooX'); + } catch(e) { } + fi.emit('data', 'bar'); + assert.equal(keys.join(''), 'fooXbar'); + rli.close(); + // calling readline without `new` fi = new FakeInput(); rli = readline.Interface({ input: fi, output: fi, terminal: terminal });