Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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).
  • Loading branch information
addaleax committed Jan 25, 2019
commit 4262977d31a3aaee577502ccbb20fb6d3809c5cc
40 changes: 23 additions & 17 deletions src/stream_pipe.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

using v8::Context;
using v8::External;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Local;
Expand Down Expand Up @@ -77,30 +78,35 @@ 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`.
Local<Value> null = Null(env->isolate());

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());

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->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;
}

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());
}

Expand Down