src: make StreamPipe::Unpipe() more resilient

Clean up `StreamPipe::Unpipe()` to be more resilient against
unexpected exceptions, in particular while executing its
`MakeCallback()` line (which can fail in the presence of
termination exceptions), and clean up the getter/setter part
of the code to match that pattern as well (even though it should
not fail as part of regular operations).

PR-URL: https://github.com/nodejs/node/pull/25716
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
This commit is contained in:
Anna Henningsen 2019-01-26 00:13:01 +01:00 committed by Daniel Bevenius
parent 0dfd5a55d6
commit 16362cb868

View File

@ -4,6 +4,7 @@
using v8::Context;
using v8::External;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Local;
@ -77,8 +78,12 @@ void StreamPipe::Unpipe() {
Context::Scope context_scope(env->context());
Local<Object> object = pipe->object();
if (object->Has(env->context(), env->onunpipe_string()).FromJust()) {
pipe->MakeCallback(env->onunpipe_string(), 0, nullptr).ToLocalChecked();
Local<Value> onunpipe;
if (!object->Get(env->context(), env->onunpipe_string()).ToLocal(&onunpipe))
return;
if (onunpipe->IsFunction() &&
pipe->MakeCallback(onunpipe.As<Function>(), 0, nullptr).IsEmpty()) {
return;
}
// Set all the links established in the constructor to `null`.
@ -86,21 +91,22 @@ void StreamPipe::Unpipe() {
Local<Value> source_v;
Local<Value> sink_v;
source_v = object->Get(env->context(), env->source_string())
.ToLocalChecked();
sink_v = object->Get(env->context(), env->sink_string())
.ToLocalChecked();
CHECK(source_v->IsObject());
CHECK(sink_v->IsObject());
if (!object->Get(env->context(), env->source_string()).ToLocal(&source_v) ||
!object->Get(env->context(), env->sink_string()).ToLocal(&sink_v) ||
!source_v->IsObject() || !sink_v->IsObject()) {
return;
}
object->Set(env->context(), env->source_string(), null).FromJust();
object->Set(env->context(), env->sink_string(), null).FromJust();
source_v.As<Object>()->Set(env->context(),
env->pipe_target_string(),
null).FromJust();
sink_v.As<Object>()->Set(env->context(),
env->pipe_source_string(),
null).FromJust();
if (object->Set(env->context(), env->source_string(), null).IsNothing() ||
object->Set(env->context(), env->sink_string(), null).IsNothing() ||
source_v.As<Object>()
->Set(env->context(), env->pipe_target_string(), null)
.IsNothing() ||
sink_v.As<Object>()
->Set(env->context(), env->pipe_source_string(), null)
.IsNothing()) {
return;
}
}, static_cast<void*>(this), object());
}