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