◐ Shell
clean mode source ↗

src: do proper error checking in `AsyncWrap::MakeCallback` · nodejs/node@671346e

Original file line numberDiff line numberDiff line change

@@ -81,18 +81,14 @@ inline v8::MaybeLocal<v8::Value> AsyncWrap::MakeCallback(

8181

const v8::Local<v8::Name> symbol,

8282

int argc,

8383

v8::Local<v8::Value>* argv) {

84-

v8::Local<v8::Value> cb_v = object()->Get(symbol);

85-

CHECK(cb_v->IsFunction());

86-

return MakeCallback(cb_v.As<v8::Function>(), argc, argv);

87-

}

88-
89-
90-

inline v8::MaybeLocal<v8::Value> AsyncWrap::MakeCallback(

91-

uint32_t index,

92-

int argc,

93-

v8::Local<v8::Value>* argv) {

94-

v8::Local<v8::Value> cb_v = object()->Get(index);

95-

CHECK(cb_v->IsFunction());

84+

v8::Local<v8::Value> cb_v;

85+

if (!object()->Get(env()->context(), symbol).ToLocal(&cb_v))

86+

return v8::MaybeLocal<v8::Value>();

87+

if (!cb_v->IsFunction()) {

88+

// TODO(addaleax): We should throw an error here to fulfill the

89+

// `MaybeLocal<>` API contract.

90+

return v8::MaybeLocal<v8::Value>();

91+

}

9692

return MakeCallback(cb_v.As<v8::Function>(), argc, argv);

9793

}

9894
Original file line numberDiff line numberDiff line change

@@ -173,9 +173,6 @@ class AsyncWrap : public BaseObject {

173173

const v8::Local<v8::Name> symbol,

174174

int argc,

175175

v8::Local<v8::Value>* argv);

176-

inline v8::MaybeLocal<v8::Value> MakeCallback(uint32_t index,

177-

int argc,

178-

v8::Local<v8::Value>* argv);

179176
180177

virtual size_t self_size() const = 0;

181178

virtual std::string diagnostic_name() const;

Original file line numberDiff line numberDiff line change

@@ -83,6 +83,10 @@ class HandleWrap : public AsyncWrap {

8383

void MarkAsInitialized();

8484

void MarkAsUninitialized();

8585
86+

inline bool IsHandleClosing() const {

87+

return state_ == kClosing || state_ == kClosed;

88+

}

89+
8690

private:

8791

friend class Environment;

8892

friend void GetActiveHandles(const v8::FunctionCallbackInfo<v8::Value>&);

Original file line numberDiff line numberDiff line change

@@ -391,9 +391,21 @@ uv_async_t* MessagePort::async() {

391391

}

392392
393393

void MessagePort::TriggerAsync() {

394+

if (IsHandleClosing()) return;

394395

CHECK_EQ(uv_async_send(async()), 0);

395396

}

396397
398+

void MessagePort::Close(v8::Local<v8::Value> close_callback) {

399+

if (data_) {

400+

// Wrap this call with accessing the mutex, so that TriggerAsync()

401+

// can check IsHandleClosing() without race conditions.

402+

Mutex::ScopedLock sibling_lock(data_->mutex_);

403+

HandleWrap::Close(close_callback);

404+

} else {

405+

HandleWrap::Close(close_callback);

406+

}

407+

}

408+
397409

void MessagePort::New(const FunctionCallbackInfo<Value>& args) {

398410

Environment* env = Environment::GetCurrent(args);

399411

if (!args.IsConstructCall()) {

@@ -476,7 +488,6 @@ void MessagePort::OnMessage() {

476488

};

477489
478490

if (args[0].IsEmpty() ||

479-

!object()->Has(context, env()->onmessage_string()).FromMaybe(false) ||

480491

MakeCallback(env()->onmessage_string(), 1, args).IsEmpty()) {

481492

// Re-schedule OnMessage() execution in case of failure.

482493

if (data_)

Original file line numberDiff line numberDiff line change

@@ -154,6 +154,8 @@ class MessagePort : public HandleWrap {

154154

std::unique_ptr<MessagePortData> Detach();

155155
156156

bool IsSiblingClosed() const;

157+

void Close(

158+

v8::Local<v8::Value> close_callback = v8::Local<v8::Value>()) override;

157159
158160

size_t self_size() const override;

159161
Original file line numberDiff line numberDiff line change

@@ -0,0 +1,49 @@

1+

// Flags: --experimental-worker

2+

'use strict';

3+

const common = require('../common');

4+

const assert = require('assert');

5+
6+

const { MessageChannel } = require('worker_threads');

7+
8+

{

9+

const { port1, port2 } = new MessageChannel();

10+
11+

// Returning a non-function in the getter should not crash.

12+

Object.defineProperty(port1, 'onmessage', {

13+

get() {

14+

port1.unref();

15+

return 42;

16+

}

17+

});

18+
19+

port2.postMessage({ foo: 'bar' });

20+
21+

// We need to start the port manually because .onmessage assignment tracking

22+

// has been overridden.

23+

port1.start();

24+

port1.ref();

25+

}

26+
27+

{

28+

const err = new Error('eyecatcher');

29+

process.on('uncaughtException', common.mustCall((exception) => {

30+

port1.unref();

31+

assert.strictEqual(exception, err);

32+

}));

33+
34+

const { port1, port2 } = new MessageChannel();

35+
36+

// Throwing in the getter should not crash.

37+

Object.defineProperty(port1, 'onmessage', {

38+

get() {

39+

throw err;

40+

}

41+

});

42+
43+

port2.postMessage({ foo: 'bar' });

44+
45+

// We need to start the port manually because .onmessage assignment tracking

46+

// has been overridden.

47+

port1.start();

48+

port1.ref();

49+

}