Skip to content

Commit 64688d8

Browse files
trevnorrisaddaleax
authored andcommitted
async_wrap: return undefined if domain is disposed
v8::MaybeLocal::ToLocalChecked() will abort on an empty handle. AsyncWrap::MakeCallback returns an empty handle if the domain is disposed, but this should not cause the process to abort. So instead return v8::Undefined() and allow the error to be handled normally. PR-URL: #14722 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Refael Ackermann <refack@gmail.com>
1 parent 11a2ca2 commit 64688d8

File tree

2 files changed

+28
-2
lines changed

2 files changed

+28
-2
lines changed

src/async-wrap.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ using v8::String;
5454
using v8::Symbol;
5555
using v8::TryCatch;
5656
using v8::Uint32Array;
57+
using v8::Undefined;
5758
using v8::Value;
5859

5960
using AsyncHooks = node::Environment::AsyncHooks;
@@ -687,7 +688,7 @@ MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
687688
get_trigger_id());
688689

689690
if (!PreCallbackExecution(this, true)) {
690-
return MaybeLocal<Value>();
691+
return Undefined(env()->isolate());
691692
}
692693

693694
// Finally... Get to running the user's callback.
@@ -698,7 +699,7 @@ MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
698699
}
699700

700701
if (!PostCallbackExecution(this, true)) {
701-
return Local<Value>();
702+
return Undefined(env()->isolate());
702703
}
703704

704705
exec_scope.Dispose();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const domain = require('domain');
6+
7+
// These were picked arbitrarily and are only used to trigger arync_hooks.
8+
const JSStream = process.binding('js_stream').JSStream;
9+
const Socket = require('net').Socket;
10+
11+
const handle = new JSStream();
12+
handle.domain = domain.create();
13+
handle.domain.dispose();
14+
15+
handle.close = () => {};
16+
handle.isAlive = () => { throw new Error(); };
17+
18+
const s = new Socket({ handle });
19+
20+
// When AsyncWrap::MakeCallback() returned an empty handle the
21+
// MaybeLocal::ToLocalChecked() call caused the process to abort. By returning
22+
// v8::Undefined() it allows the error to propagate to the 'error' event.
23+
s.on('error', common.mustCall((e) => {
24+
assert.strictEqual(e.code, 'EINVAL');
25+
}));

0 commit comments

Comments
 (0)