Skip to content
Permalink
Browse files

src: make StreamBase prototype accessors robust

This PR makes the prototype accessors added by StreamBase::AddMethods
nonenumerable and checks the signatures in the accessors so they
throw instead of raising assertions when called with incompatible
receivers. They could be enumerated when inspecting the prototype
with util.inspect or the inspector protocol.

PR-URL: #16860
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information...
joyeecheung authored and MylesBorins committed Nov 7, 2017
1 parent 2a1ebae commit a368e5fa63c8f6fe47a1d80ef15cb4ee2465f130
@@ -11,6 +11,7 @@

namespace node {

using v8::AccessorSignature;
using v8::External;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@@ -29,27 +30,33 @@ void StreamBase::AddMethods(Environment* env,
HandleScope scope(env->isolate());

enum PropertyAttribute attributes =
static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
static_cast<PropertyAttribute>(
v8::ReadOnly | v8::DontDelete | v8::DontEnum);
Local<AccessorSignature> signature =
AccessorSignature::New(env->isolate(), t);
t->PrototypeTemplate()->SetAccessor(env->fd_string(),
GetFD<Base>,
nullptr,
env->as_external(),
v8::DEFAULT,
attributes);
attributes,
signature);

t->PrototypeTemplate()->SetAccessor(env->external_stream_string(),
GetExternal<Base>,
nullptr,
env->as_external(),
v8::DEFAULT,
attributes);
attributes,
signature);

t->PrototypeTemplate()->SetAccessor(env->bytes_read_string(),
GetBytesRead<Base>,
nullptr,
env->as_external(),
v8::DEFAULT,
attributes);
attributes,
signature);

env->SetProtoMethod(t, "readStart", JSMethod<Base, &StreamBase::ReadStart>);
env->SetProtoMethod(t, "readStop", JSMethod<Base, &StreamBase::ReadStop>);
@@ -0,0 +1,19 @@
'use strict';

require('../common');

// This tests that the prototype accessors added by StreamBase::AddMethods
// are not enumerable. They could be enumerated when inspecting the prototype
// with util.inspect or the inspector protocol.

const assert = require('assert');

// Or anything that calls StreamBase::AddMethods when setting up its prototype
const TTY = process.binding('tty_wrap').TTY;

{
assert.strictEqual(TTY.prototype.propertyIsEnumerable('bytesRead'), false);
assert.strictEqual(TTY.prototype.propertyIsEnumerable('fd'), false);
assert.strictEqual(
TTY.prototype.propertyIsEnumerable('_externalStream'), false);
}
@@ -0,0 +1,27 @@
'use strict';

require('../common');

// This tests that the prototype accessors added by StreamBase::AddMethods
// do not raise assersions when called with incompatible receivers.

const assert = require('assert');

// Or anything that calls StreamBase::AddMethods when setting up its prototype
const TTY = process.binding('tty_wrap').TTY;

// Should throw instead of raise assertions
{
const msg = /TypeError: Method \w+ called on incompatible receiver/;
assert.throws(() => {
TTY.prototype.bytesRead;
}, msg);

assert.throws(() => {
TTY.prototype.fd;
}, msg);

assert.throws(() => {
TTY.prototype._externalStream;
}, msg);
}

0 comments on commit a368e5f

Please sign in to comment.
You can’t perform that action at this time.