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: https://github.com/nodejs/node/pull/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>
This commit is contained in:
Joyee Cheung 2017-11-07 19:28:06 +08:00
parent e6245030b1
commit 1ee32444ca
3 changed files with 57 additions and 4 deletions

View File

@ -11,6 +11,7 @@
namespace node {
using v8::AccessorSignature;
using v8::External;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
@ -31,27 +32,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>);

View File

@ -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);
}

View File

@ -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);
}