Browse Source

stream: fix `Writable` subclass instanceof checks

2a4b068aca introduced a regression in where checking
`instanceof` would fail for `Writable` subclasses inside the
subclass constructor, i.e. before `Writable()` was called.

Also, calling `null instanceof Writable` or
`undefined instanceof Writable` would fail due to accessing the
`_writableState` property of the target object.

This fixes these problems.

PR-URL: https://github.com/nodejs/node/pull/9088
Ref: https://github.com/nodejs/node/pull/8834#issuecomment-253640692
Reviewed-By: Ilkka Myller <ilkka.myller@nodefield.com>
Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Evan Lucas <evanlucas@me.com>
v6.x
Anna Henningsen 8 years ago
committed by Evan Lucas
parent
commit
8c4fab0a28
  1. 11
      lib/_stream_writable.js
  2. 16
      test/parallel/test-stream-inheritance.js

11
lib/_stream_writable.js

@ -141,9 +141,10 @@ if (typeof Symbol === 'function' && Symbol.hasInstance) {
realHasInstance = Function.prototype[Symbol.hasInstance]; realHasInstance = Function.prototype[Symbol.hasInstance];
Object.defineProperty(Writable, Symbol.hasInstance, { Object.defineProperty(Writable, Symbol.hasInstance, {
value: function(object) { value: function(object) {
// Trying to move the `realHasInstance` from the Writable constructor if (realHasInstance.call(this, object))
// to here will break the Node.js LazyTransform implementation. return true;
return object._writableState instanceof WritableState;
return object && object._writableState instanceof WritableState;
} }
}); });
} else { } else {
@ -156,6 +157,10 @@ function Writable(options) {
// Writable ctor is applied to Duplexes, too. // Writable ctor is applied to Duplexes, too.
// `realHasInstance` is necessary because using plain `instanceof` // `realHasInstance` is necessary because using plain `instanceof`
// would return false, as no `_writableState` property is attached. // would return false, as no `_writableState` property is attached.
// Trying to use the custom `instanceof` for Writable here will also break the
// Node.js LazyTransform implementation, which has a non-trivial getter for
// `_writableState` that would lead to infinite recursion.
if (!(realHasInstance.call(Writable, this)) && if (!(realHasInstance.call(Writable, this)) &&
!(this instanceof Stream.Duplex)) { !(this instanceof Stream.Duplex)) {
return new Writable(options); return new Writable(options);

16
test/parallel/test-stream-inheritance.js

@ -27,3 +27,19 @@ assert.ok(!(readable instanceof Transform));
assert.ok(!(writable instanceof Transform)); assert.ok(!(writable instanceof Transform));
assert.ok(!(duplex instanceof Transform)); assert.ok(!(duplex instanceof Transform));
assert.ok(transform instanceof Transform); assert.ok(transform instanceof Transform);
assert.ok(!(null instanceof Writable));
assert.ok(!(undefined instanceof Writable));
// Simple inheritance check for `Writable` works fine in a subclass constructor.
function CustomWritable() {
assert.ok(this instanceof Writable, 'inherits from Writable');
assert.ok(this instanceof CustomWritable, 'inherits from CustomWritable');
}
Object.setPrototypeOf(CustomWritable, Writable);
Object.setPrototypeOf(CustomWritable.prototype, Writable.prototype);
new CustomWritable();
assert.throws(CustomWritable, /AssertionError: inherits from Writable/);

Loading…
Cancel
Save