Skip to content

Commit ac0a0a6

Browse files
addaleaxevanlucas
authored andcommitted
src: harden JSStream callbacks
Since these are executing JS code, and in particular parts of that code may be provided by userland, handle such exceptions in C++. Refs: #17938 (comment) PR-URL: #18028 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Daniel Bevenius <[email protected]> Reviewed-By: Tiancheng "Timothy" Gu <[email protected]>
1 parent 2aeb025 commit ac0a0a6

File tree

2 files changed

+63
-13
lines changed

2 files changed

+63
-13
lines changed

src/js_stream.cc

+44-13
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ using v8::FunctionCallbackInfo;
1414
using v8::FunctionTemplate;
1515
using v8::HandleScope;
1616
using v8::Local;
17-
using v8::MaybeLocal;
1817
using v8::Object;
1918
using v8::String;
19+
using v8::TryCatch;
2020
using v8::Value;
2121

2222

@@ -87,24 +87,41 @@ bool JSStream::IsAlive() {
8787
bool JSStream::IsClosing() {
8888
HandleScope scope(env()->isolate());
8989
Context::Scope context_scope(env()->context());
90-
return MakeCallback(env()->isclosing_string(), 0, nullptr)
91-
.ToLocalChecked()->IsTrue();
90+
TryCatch try_catch(env()->isolate());
91+
Local<Value> value;
92+
if (!MakeCallback(env()->isclosing_string(), 0, nullptr).ToLocal(&value)) {
93+
FatalException(env()->isolate(), try_catch);
94+
return true;
95+
}
96+
return value->IsTrue();
9297
}
9398

9499

95100
int JSStream::ReadStart() {
96101
HandleScope scope(env()->isolate());
97102
Context::Scope context_scope(env()->context());
98-
return MakeCallback(env()->onreadstart_string(), 0, nullptr)
99-
.ToLocalChecked()->Int32Value();
103+
TryCatch try_catch(env()->isolate());
104+
Local<Value> value;
105+
int value_int = UV_EPROTO;
106+
if (!MakeCallback(env()->onreadstart_string(), 0, nullptr).ToLocal(&value) ||
107+
!value->Int32Value(env()->context()).To(&value_int)) {
108+
FatalException(env()->isolate(), try_catch);
109+
}
110+
return value_int;
100111
}
101112

102113

103114
int JSStream::ReadStop() {
104115
HandleScope scope(env()->isolate());
105116
Context::Scope context_scope(env()->context());
106-
return MakeCallback(env()->onreadstop_string(), 0, nullptr)
107-
.ToLocalChecked()->Int32Value();
117+
TryCatch try_catch(env()->isolate());
118+
Local<Value> value;
119+
int value_int = UV_EPROTO;
120+
if (!MakeCallback(env()->onreadstop_string(), 0, nullptr).ToLocal(&value) ||
121+
!value->Int32Value(env()->context()).To(&value_int)) {
122+
FatalException(env()->isolate(), try_catch);
123+
}
124+
return value_int;
108125
}
109126

110127

@@ -117,10 +134,17 @@ int JSStream::DoShutdown(ShutdownWrap* req_wrap) {
117134
};
118135

119136
req_wrap->Dispatched();
120-
MaybeLocal<Value> res =
121-
MakeCallback(env()->onshutdown_string(), arraysize(argv), argv);
122137

123-
return res.ToLocalChecked()->Int32Value();
138+
TryCatch try_catch(env()->isolate());
139+
Local<Value> value;
140+
int value_int = UV_EPROTO;
141+
if (!MakeCallback(env()->onshutdown_string(),
142+
arraysize(argv),
143+
argv).ToLocal(&value) ||
144+
!value->Int32Value(env()->context()).To(&value_int)) {
145+
FatalException(env()->isolate(), try_catch);
146+
}
147+
return value_int;
124148
}
125149

126150

@@ -146,10 +170,17 @@ int JSStream::DoWrite(WriteWrap* w,
146170
};
147171

148172
w->Dispatched();
149-
MaybeLocal<Value> res =
150-
MakeCallback(env()->onwrite_string(), arraysize(argv), argv);
151173

152-
return res.ToLocalChecked()->Int32Value();
174+
TryCatch try_catch(env()->isolate());
175+
Local<Value> value;
176+
int value_int = UV_EPROTO;
177+
if (!MakeCallback(env()->onwrite_string(),
178+
arraysize(argv),
179+
argv).ToLocal(&value) ||
180+
!value->Int32Value(env()->context()).To(&value_int)) {
181+
FatalException(env()->isolate(), try_catch);
182+
}
183+
return value_int;
153184
}
154185

155186

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Flags: --expose-internals
2+
'use strict';
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const JSStreamWrap = require('internal/wrap_js_stream');
6+
const { Duplex } = require('stream');
7+
8+
process.once('uncaughtException', common.mustCall((err) => {
9+
assert.strictEqual(err.message, 'exception!');
10+
}));
11+
12+
const socket = new JSStreamWrap(new Duplex({
13+
read: common.mustCall(),
14+
write: common.mustCall((buffer, data, cb) => {
15+
throw new Error('exception!');
16+
})
17+
}));
18+
19+
assert.throws(() => socket.end('foo'), /Error: write EPROTO/);

0 commit comments

Comments
 (0)