Skip to content

Commit ee71952

Browse files
addaleaxrvagg
authored andcommitted
src: check HasCaught() in JSStream calls
`MakeCallback` can return an empty `MaybeLocal<>` even if no exception has been generated, in particular, if we were already terminating the current thread *before* the `TryCatch` scope started, which meant it would not have an exception to report. PR-URL: #26124 Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent db94ab7 commit ee71952

File tree

2 files changed

+44
-5
lines changed

2 files changed

+44
-5
lines changed

src/js_stream.cc

+5-5
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ bool JSStream::IsClosing() {
4646
TryCatchScope try_catch(env());
4747
Local<Value> value;
4848
if (!MakeCallback(env()->isclosing_string(), 0, nullptr).ToLocal(&value)) {
49-
if (!try_catch.HasTerminated())
49+
if (try_catch.HasCaught() && !try_catch.HasTerminated())
5050
FatalException(env()->isolate(), try_catch);
5151
return true;
5252
}
@@ -62,7 +62,7 @@ int JSStream::ReadStart() {
6262
int value_int = UV_EPROTO;
6363
if (!MakeCallback(env()->onreadstart_string(), 0, nullptr).ToLocal(&value) ||
6464
!value->Int32Value(env()->context()).To(&value_int)) {
65-
if (!try_catch.HasTerminated())
65+
if (try_catch.HasCaught() && !try_catch.HasTerminated())
6666
FatalException(env()->isolate(), try_catch);
6767
}
6868
return value_int;
@@ -77,7 +77,7 @@ int JSStream::ReadStop() {
7777
int value_int = UV_EPROTO;
7878
if (!MakeCallback(env()->onreadstop_string(), 0, nullptr).ToLocal(&value) ||
7979
!value->Int32Value(env()->context()).To(&value_int)) {
80-
if (!try_catch.HasTerminated())
80+
if (try_catch.HasCaught() && !try_catch.HasTerminated())
8181
FatalException(env()->isolate(), try_catch);
8282
}
8383
return value_int;
@@ -99,7 +99,7 @@ int JSStream::DoShutdown(ShutdownWrap* req_wrap) {
9999
arraysize(argv),
100100
argv).ToLocal(&value) ||
101101
!value->Int32Value(env()->context()).To(&value_int)) {
102-
if (!try_catch.HasTerminated())
102+
if (try_catch.HasCaught() && !try_catch.HasTerminated())
103103
FatalException(env()->isolate(), try_catch);
104104
}
105105
return value_int;
@@ -134,7 +134,7 @@ int JSStream::DoWrite(WriteWrap* w,
134134
arraysize(argv),
135135
argv).ToLocal(&value) ||
136136
!value->Int32Value(env()->context()).To(&value_int)) {
137-
if (!try_catch.HasTerminated())
137+
if (try_catch.HasCaught() && !try_catch.HasTerminated())
138138
FatalException(env()->isolate(), try_catch);
139139
}
140140
return value_int;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
'use strict';
2+
const common = require('../common');
3+
if (!common.hasCrypto)
4+
common.skip('missing crypto');
5+
6+
const assert = require('assert');
7+
const http2 = require('http2');
8+
const { Duplex } = require('stream');
9+
const { Worker, workerData } = require('worker_threads');
10+
11+
// Tests the interaction between terminating a Worker thread and running
12+
// the native SetImmediate queue, which may attempt to perform multiple
13+
// calls into JS even though one already terminates the Worker.
14+
15+
if (!workerData) {
16+
const counter = new Int32Array(new SharedArrayBuffer(4));
17+
const worker = new Worker(__filename, { workerData: { counter } });
18+
worker.on('exit', common.mustCall(() => {
19+
assert.strictEqual(counter[0], 1);
20+
}));
21+
} else {
22+
const { counter } = workerData;
23+
24+
// Start two HTTP/2 connections. This will trigger write()s call from inside
25+
// the SetImmediate queue.
26+
for (let i = 0; i < 2; i++) {
27+
http2.connect('http://localhost', {
28+
createConnection() {
29+
return new Duplex({
30+
write(chunk, enc, cb) {
31+
Atomics.add(counter, 0, 1);
32+
process.exit();
33+
},
34+
read() { }
35+
});
36+
}
37+
});
38+
}
39+
}

0 commit comments

Comments
 (0)