From 0c4d5c6912ecc0d6c08d89b6ee410fc8e6a7f283 Mon Sep 17 00:00:00 2001 From: Stefano Vozza Date: Sun, 7 Aug 2016 09:34:18 +0100 Subject: [PATCH] add fix for null pointer exception in _next_fn (issue 518) --- lib/index.js | 12 +++++++++--- test/test.js | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/index.js b/lib/index.js index 6e27fca..9ff6531 100755 --- a/lib/index.js +++ b/lib/index.js @@ -770,14 +770,16 @@ function Stream(generator) { }; this._next_fn = function (xs) { - // console.log(self.id, '_next', xs, self.paused); + if (self._explicitly_destroyed) { + return; + } // It's possible to get into a situation where a call to next() is // scheduled asynchonously, but before it is run, destroy() is called, // usually by a downstream consumer like take(1). The call to next() // still completes, and there is nothing the original caller can do can // do. We do not want to throw in that situation. - if (self._nil_pushed && !self._explicitly_destroyed) { + if (self._nil_pushed) { throw new Error('Cannot call next after nil'); } @@ -1227,7 +1229,11 @@ addMethod('destroy', function () { }); Stream.prototype._writeOutgoing = function _writeOutgoing(token) { - if (this._nil_pushed && !this._explicitly_destroyed) { + if (this._explicitly_destroyed) { + return; + } + + if (this._nil_pushed) { throw new Error('Cannot write to stream after nil'); } diff --git a/test/test.js b/test/test.js index 96d9068..80a10bf 100755 --- a/test/test.js +++ b/test/test.js @@ -1040,6 +1040,30 @@ exports.GeneratorStream = { test.ok(push.called, 'The push function should have been called.'); test.ok(!push.threw(), 'The push function call should not have thrown.'); test.done(); + }, + 'Cannot read property __ConsumeGenerator__ of null (#518)': function (test) { + var clock = sinon.useFakeTimers(); + + var s = _(function (push, next) { + setTimeout(function () { + push(new Error('error')); + _.setImmediate(next); // next2 + next(); // next1 + }, 0); + }); + + s.pull(function (err, x) { + s.pull(function () { + }); + + _.setImmediate(function () { + s.destroy(); + }); + }); + + clock.tick(100); + clock.restore(); + test.done(); } };