diff --git a/src/spawn_sync.cc b/src/spawn_sync.cc index df2fb4bd3adf8b..9a259e24820c41 100644 --- a/src/spawn_sync.cc +++ b/src/spawn_sync.cc @@ -22,6 +22,7 @@ #include "spawn_sync.h" #include "debug_utils-inl.h" #include "env-inl.h" +#include "node_errors.h" #include "node_external_reference.h" #include "node_internals.h" #include "string_bytes.h" @@ -185,15 +186,17 @@ void SyncProcessStdioPipe::Close() { lifecycle_ = kClosing; } - -Local SyncProcessStdioPipe::GetOutputAsBuffer(Environment* env) const { +MaybeLocal SyncProcessStdioPipe::GetOutputAsBuffer( + Environment* env) const { size_t length = OutputLength(); - Local js_buffer = Buffer::New(env, length).ToLocalChecked(); + Local js_buffer; + if (!Buffer::New(env, length).ToLocal(&js_buffer)) { + return MaybeLocal(); + } CopyOutput(Buffer::Data(js_buffer)); return js_buffer; } - bool SyncProcessStdioPipe::readable() const { return readable_; } @@ -446,7 +449,10 @@ MaybeLocal SyncProcessRunner::Run(Local options) { CloseHandlesAndDeleteLoop(); if (r.IsNothing()) return MaybeLocal(); - Local result = BuildResultObject(); + Local result; + if (!BuildResultObject().ToLocal(&result)) { + return MaybeLocal(); + } return scope.Escape(result); } @@ -679,58 +685,80 @@ void SyncProcessRunner::SetPipeError(int pipe_error) { pipe_error_ = pipe_error; } - -Local SyncProcessRunner::BuildResultObject() { +MaybeLocal SyncProcessRunner::BuildResultObject() { EscapableHandleScope scope(env()->isolate()); Local context = env()->context(); Local js_result = Object::New(env()->isolate()); - if (GetError() != 0) { - js_result->Set(context, env()->error_string(), - Integer::New(env()->isolate(), GetError())).Check(); + if (GetError() != 0 && js_result + ->Set(context, + env()->error_string(), + Integer::New(env()->isolate(), GetError())) + .IsNothing()) { + return MaybeLocal(); } if (exit_status_ >= 0) { if (term_signal_ > 0) { - js_result->Set(context, env()->status_string(), - Null(env()->isolate())).Check(); - } else { - js_result->Set(context, env()->status_string(), - Number::New(env()->isolate(), - static_cast(exit_status_))).Check(); + if (js_result + ->Set(context, env()->status_string(), Null(env()->isolate())) + .IsNothing()) { + return MaybeLocal(); + } + } else if (js_result + ->Set(context, + env()->status_string(), + Number::New(env()->isolate(), + static_cast(exit_status_))) + .IsNothing()) { + return MaybeLocal(); } - } else { // If exit_status_ < 0 the process was never started because of some error. - js_result->Set(context, env()->status_string(), - Null(env()->isolate())).Check(); + } else if (js_result + ->Set(context, env()->status_string(), Null(env()->isolate())) + .IsNothing()) { + return MaybeLocal(); } - if (term_signal_ > 0) - js_result - ->Set(context, - env()->signal_string(), - OneByteString(env()->isolate(), signo_string(term_signal_))) - .Check(); - else - js_result->Set(context, env()->signal_string(), - Null(env()->isolate())).Check(); + if (term_signal_ > 0) { + if (js_result + ->Set(context, + env()->signal_string(), + OneByteString(env()->isolate(), signo_string(term_signal_))) + .IsNothing()) { + return MaybeLocal(); + } + } else if (js_result + ->Set(context, env()->signal_string(), Null(env()->isolate())) + .IsNothing()) { + return MaybeLocal(); + } - if (exit_status_ >= 0) - js_result->Set(context, env()->output_string(), - BuildOutputArray()).Check(); - else - js_result->Set(context, env()->output_string(), - Null(env()->isolate())).Check(); + if (exit_status_ >= 0) { + Local out; + if (!BuildOutputArray().ToLocal(&out) || + js_result->Set(context, env()->output_string(), out).IsNothing()) { + return MaybeLocal(); + } + } else if (js_result + ->Set(context, env()->output_string(), Null(env()->isolate())) + .IsNothing()) { + return MaybeLocal(); + } - js_result->Set(context, env()->pid_string(), - Number::New(env()->isolate(), uv_process_.pid)).Check(); + if (js_result + ->Set(context, + env()->pid_string(), + Number::New(env()->isolate(), uv_process_.pid)) + .IsNothing()) { + return MaybeLocal(); + } return scope.Escape(js_result); } - -Local SyncProcessRunner::BuildOutputArray() { +MaybeLocal SyncProcessRunner::BuildOutputArray() { CHECK_GE(lifecycle_, kInitialized); CHECK(!stdio_pipes_.empty()); @@ -739,10 +767,14 @@ Local SyncProcessRunner::BuildOutputArray() { for (uint32_t i = 0; i < stdio_pipes_.size(); i++) { SyncProcessStdioPipe* h = stdio_pipes_[i].get(); - if (h != nullptr && h->writable()) - js_output[i] = h->GetOutputAsBuffer(env()); - else + if (h == nullptr || !h->writable()) { js_output[i] = Null(env()->isolate()); + continue; + } + + if (!h->GetOutputAsBuffer(env()).ToLocal(&js_output[i])) { + return MaybeLocal(); + } } return scope.Escape( @@ -759,9 +791,11 @@ Maybe SyncProcessRunner::ParseOptions(Local js_value) { Local context = env()->context(); Local js_options = js_value.As(); - Local js_file = - js_options->Get(context, env()->file_string()).ToLocalChecked(); - if (!CopyJsString(js_file, &file_buffer_).To(&r)) return Nothing(); + Local js_file; + if (!js_options->Get(context, env()->file_string()).ToLocal(&js_file) || + !CopyJsString(js_file, &file_buffer_).To(&r)) { + return Nothing(); + } if (r < 0) return Just(r); uv_process_options_.file = file_buffer_; @@ -774,104 +808,154 @@ Maybe SyncProcessRunner::ParseOptions(Local js_value) { return Just(UV_EINVAL); #endif - Local js_args = - js_options->Get(context, env()->args_string()).ToLocalChecked(); - if (!CopyJsStringArray(js_args, &args_buffer_).To(&r)) return Nothing(); + Local js_args; + if (!js_options->Get(context, env()->args_string()).ToLocal(&js_args) || + !CopyJsStringArray(js_args, &args_buffer_).To(&r)) { + return Nothing(); + } if (r < 0) return Just(r); uv_process_options_.args = reinterpret_cast(args_buffer_); - Local js_cwd = - js_options->Get(context, env()->cwd_string()).ToLocalChecked(); - if (IsSet(js_cwd)) { - if (!CopyJsString(js_cwd, &cwd_buffer_).To(&r)) return Nothing(); + Local js_cwd; + if (!js_options->Get(context, env()->cwd_string()).ToLocal(&js_cwd)) { + return Nothing(); + } + if (!js_cwd->IsNullOrUndefined()) { + if (!CopyJsString(js_cwd, &cwd_buffer_).To(&r)) { + return Nothing(); + } if (r < 0) return Just(r); uv_process_options_.cwd = cwd_buffer_; } - Local js_env_pairs = - js_options->Get(context, env()->env_pairs_string()).ToLocalChecked(); - if (IsSet(js_env_pairs)) { - if (!CopyJsStringArray(js_env_pairs, &env_buffer_).To(&r)) + Local js_env_pairs; + if (!js_options->Get(context, env()->env_pairs_string()) + .ToLocal(&js_env_pairs)) { + return Nothing(); + } + if (!js_env_pairs->IsNullOrUndefined()) { + if (!CopyJsStringArray(js_env_pairs, &env_buffer_).To(&r)) { return Nothing(); + } if (r < 0) return Just(r); uv_process_options_.env = reinterpret_cast(env_buffer_); } - Local js_uid = - js_options->Get(context, env()->uid_string()).ToLocalChecked(); - if (IsSet(js_uid)) { - CHECK(js_uid->IsInt32()); + Local js_uid; + if (!js_options->Get(context, env()->uid_string()).ToLocal(&js_uid)) { + return Nothing(); + } + if (!js_uid->IsNullOrUndefined()) { + if (!js_uid->IsInt32()) { + THROW_ERR_INVALID_ARG_TYPE(env(), + "options.uid must be a 32-bit signed integer"); + return Nothing(); + } const int32_t uid = js_uid.As()->Value(); uv_process_options_.uid = static_cast(uid); uv_process_options_.flags |= UV_PROCESS_SETUID; } - Local js_gid = - js_options->Get(context, env()->gid_string()).ToLocalChecked(); - if (IsSet(js_gid)) { - CHECK(js_gid->IsInt32()); + Local js_gid; + if (!js_options->Get(context, env()->gid_string()).ToLocal(&js_gid)) { + return Nothing(); + } + if (!js_gid->IsNullOrUndefined()) { + if (!js_gid->IsInt32()) { + THROW_ERR_INVALID_ARG_TYPE(env(), + "options.gid must be a 32-bit signed integer"); + return Nothing(); + } const int32_t gid = js_gid.As()->Value(); uv_process_options_.gid = static_cast(gid); uv_process_options_.flags |= UV_PROCESS_SETGID; } - Local js_detached = - js_options->Get(context, env()->detached_string()).ToLocalChecked(); - if (js_detached->BooleanValue(isolate)) + Local js_detached; + if (!js_options->Get(context, env()->detached_string()) + .ToLocal(&js_detached)) { + return Nothing(); + } + if (js_detached->BooleanValue(isolate)) { uv_process_options_.flags |= UV_PROCESS_DETACHED; + } - Local js_win_hide = - js_options->Get(context, env()->windows_hide_string()).ToLocalChecked(); - if (js_win_hide->BooleanValue(isolate)) + Local js_win_hide; + if (!js_options->Get(context, env()->windows_hide_string()) + .ToLocal(&js_win_hide)) { + return Nothing(); + } + if (js_win_hide->BooleanValue(isolate)) { uv_process_options_.flags |= UV_PROCESS_WINDOWS_HIDE; + } - if (env()->hide_console_windows()) + if (env()->hide_console_windows()) { uv_process_options_.flags |= UV_PROCESS_WINDOWS_HIDE_CONSOLE; + } - Local js_wva = - js_options->Get(context, env()->windows_verbatim_arguments_string()) - .ToLocalChecked(); + Local js_wva; + if (!js_options->Get(context, env()->windows_verbatim_arguments_string()) + .ToLocal(&js_wva)) { + return Nothing(); + } - if (js_wva->BooleanValue(isolate)) + if (js_wva->BooleanValue(isolate)) { uv_process_options_.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS; + } - Local js_timeout = - js_options->Get(context, env()->timeout_string()).ToLocalChecked(); - if (IsSet(js_timeout)) { - CHECK(js_timeout->IsNumber()); + Local js_timeout; + if (!js_options->Get(context, env()->timeout_string()).ToLocal(&js_timeout)) { + return Nothing(); + } + if (!js_timeout->IsNullOrUndefined()) { + if (!js_timeout->IsNumber()) { + THROW_ERR_INVALID_ARG_TYPE(env(), "options.timeout must be a number"); + return Nothing(); + } int64_t timeout = js_timeout->IntegerValue(context).FromJust(); timeout_ = static_cast(timeout); } - Local js_max_buffer = - js_options->Get(context, env()->max_buffer_string()).ToLocalChecked(); - if (IsSet(js_max_buffer)) { - CHECK(js_max_buffer->IsNumber()); + Local js_max_buffer; + if (!js_options->Get(context, env()->max_buffer_string()) + .ToLocal(&js_max_buffer)) { + return Nothing(); + } + if (!js_max_buffer->IsNullOrUndefined()) { + if (!js_max_buffer->IsNumber()) { + THROW_ERR_INVALID_ARG_TYPE(env(), "options.maxBuffer must be a number"); + return Nothing(); + } max_buffer_ = js_max_buffer->NumberValue(context).FromJust(); } - Local js_kill_signal = - js_options->Get(context, env()->kill_signal_string()).ToLocalChecked(); - if (IsSet(js_kill_signal)) { - CHECK(js_kill_signal->IsInt32()); + Local js_kill_signal; + if (!js_options->Get(context, env()->kill_signal_string()) + .ToLocal(&js_kill_signal)) { + return Nothing(); + } + if (!js_kill_signal->IsNullOrUndefined()) { + if (!js_kill_signal->IsNumber()) { + THROW_ERR_INVALID_ARG_TYPE(env(), "options.killSignal must be a number"); + return Nothing(); + } kill_signal_ = js_kill_signal.As()->Value(); } - Local js_stdio = - js_options->Get(context, env()->stdio_string()).ToLocalChecked(); - r = ParseStdioOptions(js_stdio); - if (r < 0) return Just(r); + Local js_stdio; + if (!js_options->Get(context, env()->stdio_string()).ToLocal(&js_stdio) || + !ParseStdioOptions(js_stdio).To(&r)) { + return Nothing(); + } - return Just(0); + return Just(r); } - -int SyncProcessRunner::ParseStdioOptions(Local js_value) { +Maybe SyncProcessRunner::ParseStdioOptions(Local js_value) { HandleScope scope(env()->isolate()); Local js_stdio_options; - if (!js_value->IsArray()) - return UV_EINVAL; + if (!js_value->IsArray()) return Just(UV_EINVAL); Local context = env()->context(); js_stdio_options = js_value.As(); @@ -884,49 +968,64 @@ int SyncProcessRunner::ParseStdioOptions(Local js_value) { stdio_pipes_initialized_ = true; for (uint32_t i = 0; i < stdio_count_; i++) { - Local js_stdio_option = - js_stdio_options->Get(context, i).ToLocalChecked(); + Local js_stdio_option; + if (!js_stdio_options->Get(context, i).ToLocal(&js_stdio_option)) { + return Nothing(); + } - if (!js_stdio_option->IsObject()) - return UV_EINVAL; + if (!js_stdio_option->IsObject()) { + return Just(UV_EINVAL); + } - int r = ParseStdioOption(i, js_stdio_option.As()); - if (r < 0) - return r; + int r; + if (!ParseStdioOption(i, js_stdio_option.As()).To(&r)) { + return Nothing(); + } + if (r < 0) { + return Just(r); + } } uv_process_options_.stdio = uv_stdio_containers_; uv_process_options_.stdio_count = stdio_count_; - return 0; + return Just(0); } - -int SyncProcessRunner::ParseStdioOption(int child_fd, - Local js_stdio_option) { +Maybe SyncProcessRunner::ParseStdioOption(int child_fd, + Local js_stdio_option) { Local context = env()->context(); - Local js_type = - js_stdio_option->Get(context, env()->type_string()).ToLocalChecked(); + Local js_type; + if (!js_stdio_option->Get(context, env()->type_string()).ToLocal(&js_type)) { + return Nothing(); + } if (js_type->StrictEquals(env()->ignore_string())) { - return AddStdioIgnore(child_fd); - + return Just(AddStdioIgnore(child_fd)); } else if (js_type->StrictEquals(env()->pipe_string())) { Isolate* isolate = env()->isolate(); Local rs = env()->readable_string(); Local ws = env()->writable_string(); - bool readable = js_stdio_option->Get(context, rs) - .ToLocalChecked()->BooleanValue(isolate); - bool writable = - js_stdio_option->Get(context, ws) - .ToLocalChecked()->BooleanValue(isolate); + Local value; + if (!js_stdio_option->Get(context, rs).ToLocal(&value)) { + return Nothing(); + } + auto readable = value->BooleanValue(isolate); + + if (!js_stdio_option->Get(context, ws).ToLocal(&value)) { + return Nothing(); + } + bool writable = value->BooleanValue(isolate); uv_buf_t buf = uv_buf_init(nullptr, 0); if (readable) { - Local input = - js_stdio_option->Get(context, env()->input_string()).ToLocalChecked(); + Local input; + if (!js_stdio_option->Get(context, env()->input_string()) + .ToLocal(&input)) { + return Nothing(); + } if (Buffer::HasInstance(input)) { buf = uv_buf_init(Buffer::Data(input), static_cast(Buffer::Length(input))); @@ -934,23 +1033,25 @@ int SyncProcessRunner::ParseStdioOption(int child_fd, // Strings, numbers etc. are currently unsupported. It's not possible // to create a buffer for them here because there is no way to free // them afterwards. - return UV_EINVAL; + return Just(UV_EINVAL); } } - return AddStdioPipe(child_fd, readable, writable, buf); + return Just(AddStdioPipe(child_fd, readable, writable, buf)); } else if (js_type->StrictEquals(env()->inherit_string()) || js_type->StrictEquals(env()->fd_string())) { - int inherit_fd = js_stdio_option->Get(context, env()->fd_string()) - .ToLocalChecked()->Int32Value(context).FromJust(); - return AddStdioInheritFD(child_fd, inherit_fd); - - } else { - UNREACHABLE("invalid child stdio type"); + Local val; + int inherit_fd; + if (!js_stdio_option->Get(context, env()->fd_string()).ToLocal(&val) || + !val->Int32Value(context).To(&inherit_fd)) { + return Nothing(); + } + return Just(AddStdioInheritFD(child_fd, inherit_fd)); } -} + UNREACHABLE("invalid child stdio type"); +} int SyncProcessRunner::AddStdioIgnore(uint32_t child_fd) { CHECK_LT(child_fd, stdio_count_); @@ -997,11 +1098,6 @@ int SyncProcessRunner::AddStdioInheritFD(uint32_t child_fd, int inherit_fd) { return 0; } - -bool SyncProcessRunner::IsSet(Local value) { - return !value->IsUndefined() && !value->IsNull(); -} - Maybe SyncProcessRunner::CopyJsString(Local js_value, const char** target) { Isolate* isolate = env()->isolate(); @@ -1054,18 +1150,18 @@ Maybe SyncProcessRunner::CopyJsStringArray(Local js_value, // length of all strings, including room for a null terminator after every // string. Align strings to cache lines. for (uint32_t i = 0; i < length; i++) { - auto value = js_array->Get(context, i).ToLocalChecked(); + Local value; + if (!js_array->Get(context, i).ToLocal(&value)) { + return Nothing(); + } if (!value->IsString()) { Local string; if (!value->ToString(env()->isolate()->GetCurrentContext()) - .ToLocal(&string)) + .ToLocal(&string) || + js_array->Set(context, i, string).IsNothing()) { return Nothing(); - js_array - ->Set(context, - i, - string) - .Check(); + } } Maybe maybe_size = StringBytes::StorageSize(isolate, value, UTF8); @@ -1081,7 +1177,10 @@ Maybe SyncProcessRunner::CopyJsStringArray(Local js_value, for (uint32_t i = 0; i < length; i++) { list[i] = buffer + data_offset; - auto value = js_array->Get(context, i).ToLocalChecked(); + Local value; + if (!js_array->Get(context, i).ToLocal(&value)) { + return Nothing(); + } data_offset += StringBytes::Write(isolate, buffer + data_offset, -1, diff --git a/src/spawn_sync.h b/src/spawn_sync.h index 8243737130af1b..4478487c8f403e 100644 --- a/src/spawn_sync.h +++ b/src/spawn_sync.h @@ -82,7 +82,7 @@ class SyncProcessStdioPipe { int Start(); void Close(); - v8::Local GetOutputAsBuffer(Environment* env) const; + v8::MaybeLocal GetOutputAsBuffer(Environment* env) const; inline bool readable() const; inline bool writable() const; @@ -171,12 +171,13 @@ class SyncProcessRunner { void SetError(int error); void SetPipeError(int pipe_error); - v8::Local BuildResultObject(); - v8::Local BuildOutputArray(); + v8::MaybeLocal BuildResultObject(); + v8::MaybeLocal BuildOutputArray(); v8::Maybe ParseOptions(v8::Local js_value); - int ParseStdioOptions(v8::Local js_value); - int ParseStdioOption(int child_fd, v8::Local js_stdio_option); + v8::Maybe ParseStdioOptions(v8::Local js_value); + v8::Maybe ParseStdioOption(int child_fd, + v8::Local js_stdio_option); inline int AddStdioIgnore(uint32_t child_fd); inline int AddStdioPipe(uint32_t child_fd,