Skip to content

Commit a368e5f

Browse files
joyeecheungMylesBorins
authored andcommitted
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>
1 parent 2a1ebae commit a368e5f

3 files changed

+57
-4
lines changed

src/stream_base-inl.h

+11-4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace node {
1313

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

3132
enum PropertyAttribute attributes =
32-
static_cast<PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
33+
static_cast<PropertyAttribute>(
34+
v8::ReadOnly | v8::DontDelete | v8::DontEnum);
35+
Local<AccessorSignature> signature =
36+
AccessorSignature::New(env->isolate(), t);
3337
t->PrototypeTemplate()->SetAccessor(env->fd_string(),
3438
GetFD<Base>,
3539
nullptr,
3640
env->as_external(),
3741
v8::DEFAULT,
38-
attributes);
42+
attributes,
43+
signature);
3944

4045
t->PrototypeTemplate()->SetAccessor(env->external_stream_string(),
4146
GetExternal<Base>,
4247
nullptr,
4348
env->as_external(),
4449
v8::DEFAULT,
45-
attributes);
50+
attributes,
51+
signature);
4652

4753
t->PrototypeTemplate()->SetAccessor(env->bytes_read_string(),
4854
GetBytesRead<Base>,
4955
nullptr,
5056
env->as_external(),
5157
v8::DEFAULT,
52-
attributes);
58+
attributes,
59+
signature);
5360

5461
env->SetProtoMethod(t, "readStart", JSMethod<Base, &StreamBase::ReadStart>);
5562
env->SetProtoMethod(t, "readStop", JSMethod<Base, &StreamBase::ReadStop>);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
3+
require('../common');
4+
5+
// This tests that the prototype accessors added by StreamBase::AddMethods
6+
// are not enumerable. They could be enumerated when inspecting the prototype
7+
// with util.inspect or the inspector protocol.
8+
9+
const assert = require('assert');
10+
11+
// Or anything that calls StreamBase::AddMethods when setting up its prototype
12+
const TTY = process.binding('tty_wrap').TTY;
13+
14+
{
15+
assert.strictEqual(TTY.prototype.propertyIsEnumerable('bytesRead'), false);
16+
assert.strictEqual(TTY.prototype.propertyIsEnumerable('fd'), false);
17+
assert.strictEqual(
18+
TTY.prototype.propertyIsEnumerable('_externalStream'), false);
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict';
2+
3+
require('../common');
4+
5+
// This tests that the prototype accessors added by StreamBase::AddMethods
6+
// do not raise assersions when called with incompatible receivers.
7+
8+
const assert = require('assert');
9+
10+
// Or anything that calls StreamBase::AddMethods when setting up its prototype
11+
const TTY = process.binding('tty_wrap').TTY;
12+
13+
// Should throw instead of raise assertions
14+
{
15+
const msg = /TypeError: Method \w+ called on incompatible receiver/;
16+
assert.throws(() => {
17+
TTY.prototype.bytesRead;
18+
}, msg);
19+
20+
assert.throws(() => {
21+
TTY.prototype.fd;
22+
}, msg);
23+
24+
assert.throws(() => {
25+
TTY.prototype._externalStream;
26+
}, msg);
27+
}

0 commit comments

Comments
 (0)