• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #include "spawn_sync.h"
23 #include "debug_utils-inl.h"
24 #include "env-inl.h"
25 #include "node_internals.h"
26 #include "string_bytes.h"
27 #include "util-inl.h"
28 
29 #include <cstring>
30 
31 
32 namespace node {
33 
34 using v8::Array;
35 using v8::Context;
36 using v8::EscapableHandleScope;
37 using v8::FunctionCallbackInfo;
38 using v8::HandleScope;
39 using v8::Int32;
40 using v8::Integer;
41 using v8::Isolate;
42 using v8::Just;
43 using v8::Local;
44 using v8::Maybe;
45 using v8::MaybeLocal;
46 using v8::Nothing;
47 using v8::Null;
48 using v8::Number;
49 using v8::Object;
50 using v8::String;
51 using v8::Value;
52 
OnAlloc(size_t suggested_size,uv_buf_t * buf) const53 void SyncProcessOutputBuffer::OnAlloc(size_t suggested_size,
54                                       uv_buf_t* buf) const {
55   if (used() == kBufferSize)
56     *buf = uv_buf_init(nullptr, 0);
57   else
58     *buf = uv_buf_init(data_ + used(), available());
59 }
60 
61 
OnRead(const uv_buf_t * buf,size_t nread)62 void SyncProcessOutputBuffer::OnRead(const uv_buf_t* buf, size_t nread) {
63   // If we hand out the same chunk twice, this should catch it.
64   CHECK_EQ(buf->base, data_ + used());
65   used_ += static_cast<unsigned int>(nread);
66 }
67 
68 
Copy(char * dest) const69 size_t SyncProcessOutputBuffer::Copy(char* dest) const {
70   memcpy(dest, data_, used());
71   return used();
72 }
73 
74 
available() const75 unsigned int SyncProcessOutputBuffer::available() const {
76   return sizeof data_ - used();
77 }
78 
79 
used() const80 unsigned int SyncProcessOutputBuffer::used() const {
81   return used_;
82 }
83 
84 
next() const85 SyncProcessOutputBuffer* SyncProcessOutputBuffer::next() const {
86   return next_;
87 }
88 
89 
set_next(SyncProcessOutputBuffer * next)90 void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) {
91   next_ = next;
92 }
93 
94 
SyncProcessStdioPipe(SyncProcessRunner * process_handler,bool readable,bool writable,uv_buf_t input_buffer)95 SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler,
96                                            bool readable,
97                                            bool writable,
98                                            uv_buf_t input_buffer)
99     : process_handler_(process_handler),
100       readable_(readable),
101       writable_(writable),
102       input_buffer_(input_buffer),
103 
104       first_output_buffer_(nullptr),
105       last_output_buffer_(nullptr),
106 
107       uv_pipe_(),
108       write_req_(),
109       shutdown_req_(),
110 
111       lifecycle_(kUninitialized) {
112   CHECK(readable || writable);
113 }
114 
115 
~SyncProcessStdioPipe()116 SyncProcessStdioPipe::~SyncProcessStdioPipe() {
117   CHECK(lifecycle_ == kUninitialized || lifecycle_ == kClosed);
118 
119   SyncProcessOutputBuffer* buf;
120   SyncProcessOutputBuffer* next;
121 
122   for (buf = first_output_buffer_; buf != nullptr; buf = next) {
123     next = buf->next();
124     delete buf;
125   }
126 }
127 
128 
Initialize(uv_loop_t * loop)129 int SyncProcessStdioPipe::Initialize(uv_loop_t* loop) {
130   CHECK_EQ(lifecycle_, kUninitialized);
131 
132   int r = uv_pipe_init(loop, uv_pipe(), 0);
133   if (r < 0)
134     return r;
135 
136   uv_pipe()->data = this;
137 
138   lifecycle_ = kInitialized;
139   return 0;
140 }
141 
142 
Start()143 int SyncProcessStdioPipe::Start() {
144   CHECK_EQ(lifecycle_, kInitialized);
145 
146   // Set the busy flag already. If this function fails no recovery is
147   // possible.
148   lifecycle_ = kStarted;
149 
150   if (readable()) {
151     if (input_buffer_.len > 0) {
152       CHECK_NOT_NULL(input_buffer_.base);
153 
154       int r = uv_write(&write_req_,
155                        uv_stream(),
156                        &input_buffer_,
157                        1,
158                        WriteCallback);
159       if (r < 0)
160         return r;
161     }
162 
163     int r = uv_shutdown(&shutdown_req_, uv_stream(), ShutdownCallback);
164     if (r < 0)
165       return r;
166   }
167 
168   if (writable()) {
169     int r = uv_read_start(uv_stream(), AllocCallback, ReadCallback);
170     if (r < 0)
171       return r;
172   }
173 
174   return 0;
175 }
176 
177 
Close()178 void SyncProcessStdioPipe::Close() {
179   CHECK(lifecycle_ == kInitialized || lifecycle_ == kStarted);
180 
181   uv_close(uv_handle(), CloseCallback);
182 
183   lifecycle_ = kClosing;
184 }
185 
186 
GetOutputAsBuffer(Environment * env) const187 Local<Object> SyncProcessStdioPipe::GetOutputAsBuffer(Environment* env) const {
188   size_t length = OutputLength();
189   Local<Object> js_buffer = Buffer::New(env, length).ToLocalChecked();
190   CopyOutput(Buffer::Data(js_buffer));
191   return js_buffer;
192 }
193 
194 
readable() const195 bool SyncProcessStdioPipe::readable() const {
196   return readable_;
197 }
198 
199 
writable() const200 bool SyncProcessStdioPipe::writable() const {
201   return writable_;
202 }
203 
204 
uv_flags() const205 uv_stdio_flags SyncProcessStdioPipe::uv_flags() const {
206   unsigned int flags;
207 
208   flags = UV_CREATE_PIPE;
209   if (readable())
210     flags |= UV_READABLE_PIPE;
211   if (writable())
212     flags |= UV_WRITABLE_PIPE;
213 
214   return static_cast<uv_stdio_flags>(flags);
215 }
216 
217 
uv_pipe() const218 uv_pipe_t* SyncProcessStdioPipe::uv_pipe() const {
219   CHECK_LT(lifecycle_, kClosing);
220   return &uv_pipe_;
221 }
222 
223 
uv_stream() const224 uv_stream_t* SyncProcessStdioPipe::uv_stream() const {
225   return reinterpret_cast<uv_stream_t*>(uv_pipe());
226 }
227 
228 
uv_handle() const229 uv_handle_t* SyncProcessStdioPipe::uv_handle() const {
230   return reinterpret_cast<uv_handle_t*>(uv_pipe());
231 }
232 
233 
OutputLength() const234 size_t SyncProcessStdioPipe::OutputLength() const {
235   SyncProcessOutputBuffer* buf;
236   size_t size = 0;
237 
238   for (buf = first_output_buffer_; buf != nullptr; buf = buf->next())
239     size += buf->used();
240 
241   return size;
242 }
243 
244 
CopyOutput(char * dest) const245 void SyncProcessStdioPipe::CopyOutput(char* dest) const {
246   SyncProcessOutputBuffer* buf;
247   size_t offset = 0;
248 
249   for (buf = first_output_buffer_; buf != nullptr; buf = buf->next())
250     offset += buf->Copy(dest + offset);
251 }
252 
253 
OnAlloc(size_t suggested_size,uv_buf_t * buf)254 void SyncProcessStdioPipe::OnAlloc(size_t suggested_size, uv_buf_t* buf) {
255   // This function assumes that libuv will never allocate two buffers for the
256   // same stream at the same time. There's an assert in
257   // SyncProcessOutputBuffer::OnRead that would fail if this assumption was
258   // ever violated.
259 
260   if (last_output_buffer_ == nullptr) {
261     // Allocate the first capture buffer.
262     first_output_buffer_ = new SyncProcessOutputBuffer();
263     last_output_buffer_ = first_output_buffer_;
264 
265   } else if (last_output_buffer_->available() == 0) {
266     // The current capture buffer is full so get us a new one.
267     SyncProcessOutputBuffer* buf = new SyncProcessOutputBuffer();
268     last_output_buffer_->set_next(buf);
269     last_output_buffer_ = buf;
270   }
271 
272   last_output_buffer_->OnAlloc(suggested_size, buf);
273 }
274 
275 
OnRead(const uv_buf_t * buf,ssize_t nread)276 void SyncProcessStdioPipe::OnRead(const uv_buf_t* buf, ssize_t nread) {
277   if (nread == UV_EOF) {
278     // Libuv implicitly stops reading on EOF.
279 
280   } else if (nread < 0) {
281     SetError(static_cast<int>(nread));
282     // At some point libuv should really implicitly stop reading on error.
283     uv_read_stop(uv_stream());
284 
285   } else {
286     last_output_buffer_->OnRead(buf, nread);
287     process_handler_->IncrementBufferSizeAndCheckOverflow(nread);
288   }
289 }
290 
291 
OnWriteDone(int result)292 void SyncProcessStdioPipe::OnWriteDone(int result) {
293   if (result < 0)
294     SetError(result);
295 }
296 
297 
OnShutdownDone(int result)298 void SyncProcessStdioPipe::OnShutdownDone(int result) {
299   if (result < 0)
300     SetError(result);
301 }
302 
303 
OnClose()304 void SyncProcessStdioPipe::OnClose() {
305   lifecycle_ = kClosed;
306 }
307 
308 
SetError(int error)309 void SyncProcessStdioPipe::SetError(int error) {
310   CHECK_NE(error, 0);
311   process_handler_->SetPipeError(error);
312 }
313 
314 
AllocCallback(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)315 void SyncProcessStdioPipe::AllocCallback(uv_handle_t* handle,
316                                          size_t suggested_size,
317                                          uv_buf_t* buf) {
318   SyncProcessStdioPipe* self =
319       reinterpret_cast<SyncProcessStdioPipe*>(handle->data);
320   self->OnAlloc(suggested_size, buf);
321 }
322 
323 
ReadCallback(uv_stream_t * stream,ssize_t nread,const uv_buf_t * buf)324 void SyncProcessStdioPipe::ReadCallback(uv_stream_t* stream,
325                                         ssize_t nread,
326                                         const uv_buf_t* buf) {
327   SyncProcessStdioPipe* self =
328         reinterpret_cast<SyncProcessStdioPipe*>(stream->data);
329   self->OnRead(buf, nread);
330 }
331 
332 
WriteCallback(uv_write_t * req,int result)333 void SyncProcessStdioPipe::WriteCallback(uv_write_t* req, int result) {
334   SyncProcessStdioPipe* self =
335       reinterpret_cast<SyncProcessStdioPipe*>(req->handle->data);
336   self->OnWriteDone(result);
337 }
338 
339 
ShutdownCallback(uv_shutdown_t * req,int result)340 void SyncProcessStdioPipe::ShutdownCallback(uv_shutdown_t* req, int result) {
341   SyncProcessStdioPipe* self =
342       reinterpret_cast<SyncProcessStdioPipe*>(req->handle->data);
343 
344   // On AIX, OS X and the BSDs, calling shutdown() on one end of a pipe
345   // when the other end has closed the connection fails with ENOTCONN.
346   // Libuv is not the right place to handle that because it can't tell
347   // if the error is genuine but we here can.
348   if (result == UV_ENOTCONN)
349     result = 0;
350 
351   self->OnShutdownDone(result);
352 }
353 
354 
CloseCallback(uv_handle_t * handle)355 void SyncProcessStdioPipe::CloseCallback(uv_handle_t* handle) {
356   SyncProcessStdioPipe* self =
357       reinterpret_cast<SyncProcessStdioPipe*>(handle->data);
358   self->OnClose();
359 }
360 
361 
Initialize(Local<Object> target,Local<Value> unused,Local<Context> context,void * priv)362 void SyncProcessRunner::Initialize(Local<Object> target,
363                                    Local<Value> unused,
364                                    Local<Context> context,
365                                    void* priv) {
366   SetMethod(context, target, "spawn", Spawn);
367 }
368 
369 
Spawn(const FunctionCallbackInfo<Value> & args)370 void SyncProcessRunner::Spawn(const FunctionCallbackInfo<Value>& args) {
371   Environment* env = Environment::GetCurrent(args);
372   env->PrintSyncTrace();
373   SyncProcessRunner p(env);
374   Local<Value> result;
375   if (!p.Run(args[0]).ToLocal(&result)) return;
376   args.GetReturnValue().Set(result);
377 }
378 
379 
SyncProcessRunner(Environment * env)380 SyncProcessRunner::SyncProcessRunner(Environment* env)
381     : max_buffer_(0),
382       timeout_(0),
383       kill_signal_(SIGTERM),
384 
385       uv_loop_(nullptr),
386 
387       stdio_count_(0),
388       uv_stdio_containers_(nullptr),
389       stdio_pipes_initialized_(false),
390 
391       uv_process_options_(),
392       file_buffer_(nullptr),
393       args_buffer_(nullptr),
394       env_buffer_(nullptr),
395       cwd_buffer_(nullptr),
396 
397       uv_process_(),
398       killed_(false),
399 
400       buffered_output_size_(0),
401       exit_status_(-1),
402       term_signal_(-1),
403 
404       uv_timer_(),
405       kill_timer_initialized_(false),
406 
407       error_(0),
408       pipe_error_(0),
409 
410       lifecycle_(kUninitialized),
411 
412       env_(env) {
413 }
414 
415 
~SyncProcessRunner()416 SyncProcessRunner::~SyncProcessRunner() {
417   CHECK_EQ(lifecycle_, kHandlesClosed);
418 
419   stdio_pipes_.clear();
420   delete[] file_buffer_;
421   delete[] args_buffer_;
422   delete[] cwd_buffer_;
423   delete[] env_buffer_;
424   delete[] uv_stdio_containers_;
425 }
426 
427 
env() const428 Environment* SyncProcessRunner::env() const {
429   return env_;
430 }
431 
Run(Local<Value> options)432 MaybeLocal<Object> SyncProcessRunner::Run(Local<Value> options) {
433   EscapableHandleScope scope(env()->isolate());
434 
435   CHECK_EQ(lifecycle_, kUninitialized);
436 
437   Maybe<bool> r = TryInitializeAndRunLoop(options);
438   CloseHandlesAndDeleteLoop();
439   if (r.IsNothing()) return MaybeLocal<Object>();
440 
441   Local<Object> result = BuildResultObject();
442 
443   return scope.Escape(result);
444 }
445 
TryInitializeAndRunLoop(Local<Value> options)446 Maybe<bool> SyncProcessRunner::TryInitializeAndRunLoop(Local<Value> options) {
447   int r;
448 
449   // There is no recovery from failure inside TryInitializeAndRunLoop - the
450   // only option we'd have is to close all handles and destroy the loop.
451   CHECK_EQ(lifecycle_, kUninitialized);
452   lifecycle_ = kInitialized;
453 
454   uv_loop_ = new uv_loop_t;
455   if (uv_loop_ == nullptr) {
456     SetError(UV_ENOMEM);
457     return Just(false);
458   }
459 
460   r = uv_loop_init(uv_loop_);
461   if (r < 0) {
462     delete uv_loop_;
463     uv_loop_ = nullptr;
464     SetError(r);
465     return Just(false);
466   }
467 
468   if (!ParseOptions(options).To(&r)) return Nothing<bool>();
469 
470   if (r < 0) {
471     SetError(r);
472     return Just(false);
473   }
474 
475   if (timeout_ > 0) {
476     r = uv_timer_init(uv_loop_, &uv_timer_);
477     if (r < 0) {
478       SetError(r);
479       return Just(false);
480     }
481 
482     uv_unref(reinterpret_cast<uv_handle_t*>(&uv_timer_));
483 
484     uv_timer_.data = this;
485     kill_timer_initialized_ = true;
486 
487     // Start the timer immediately. If uv_spawn fails then
488     // CloseHandlesAndDeleteLoop() will immediately close the timer handle
489     // which implicitly stops it, so there is no risk that the timeout callback
490     // runs when the process didn't start.
491     r = uv_timer_start(&uv_timer_, KillTimerCallback, timeout_, 0);
492     if (r < 0) {
493       SetError(r);
494       return Just(false);
495     }
496   }
497 
498   uv_process_options_.exit_cb = ExitCallback;
499   r = uv_spawn(uv_loop_, &uv_process_, &uv_process_options_);
500   if (r < 0) {
501     SetError(r);
502     return Just(false);
503   }
504   uv_process_.data = this;
505 
506   for (const auto& pipe : stdio_pipes_) {
507     if (pipe != nullptr) {
508       r = pipe->Start();
509       if (r < 0) {
510         SetPipeError(r);
511         return Just(false);
512       }
513     }
514   }
515 
516   r = uv_run(uv_loop_, UV_RUN_DEFAULT);
517   if (r < 0)
518     // We can't handle uv_run failure.
519     ABORT();
520 
521   // If we get here the process should have exited.
522   CHECK_GE(exit_status_, 0);
523   return Just(true);
524 }
525 
526 
CloseHandlesAndDeleteLoop()527 void SyncProcessRunner::CloseHandlesAndDeleteLoop() {
528   CHECK_LT(lifecycle_, kHandlesClosed);
529 
530   if (uv_loop_ != nullptr) {
531     CloseStdioPipes();
532     CloseKillTimer();
533     // Close the process handle when ExitCallback was not called.
534     uv_handle_t* uv_process_handle =
535         reinterpret_cast<uv_handle_t*>(&uv_process_);
536 
537     // Close the process handle if it is still open. The handle type also
538     // needs to be checked because TryInitializeAndRunLoop() won't spawn a
539     // process if input validation fails.
540     if (uv_process_handle->type == UV_PROCESS &&
541         !uv_is_closing(uv_process_handle))
542       uv_close(uv_process_handle, nullptr);
543 
544     // Give closing watchers a chance to finish closing and get their close
545     // callbacks called.
546     int r = uv_run(uv_loop_, UV_RUN_DEFAULT);
547     if (r < 0)
548       ABORT();
549 
550     CheckedUvLoopClose(uv_loop_);
551     delete uv_loop_;
552     uv_loop_ = nullptr;
553 
554   } else {
555     // If the loop doesn't exist, neither should any pipes or timers.
556     CHECK_EQ(false, stdio_pipes_initialized_);
557     CHECK_EQ(false, kill_timer_initialized_);
558   }
559 
560   lifecycle_ = kHandlesClosed;
561 }
562 
563 
CloseStdioPipes()564 void SyncProcessRunner::CloseStdioPipes() {
565   CHECK_LT(lifecycle_, kHandlesClosed);
566 
567   if (stdio_pipes_initialized_) {
568     CHECK(!stdio_pipes_.empty());
569     CHECK_NOT_NULL(uv_loop_);
570 
571     for (const auto& pipe : stdio_pipes_) {
572       if (pipe)
573         pipe->Close();
574     }
575 
576     stdio_pipes_initialized_ = false;
577   }
578 }
579 
580 
CloseKillTimer()581 void SyncProcessRunner::CloseKillTimer() {
582   CHECK_LT(lifecycle_, kHandlesClosed);
583 
584   if (kill_timer_initialized_) {
585     CHECK_GT(timeout_, 0);
586     CHECK_NOT_NULL(uv_loop_);
587 
588     uv_handle_t* uv_timer_handle = reinterpret_cast<uv_handle_t*>(&uv_timer_);
589     uv_ref(uv_timer_handle);
590     uv_close(uv_timer_handle, KillTimerCloseCallback);
591 
592     kill_timer_initialized_ = false;
593   }
594 }
595 
596 
Kill()597 void SyncProcessRunner::Kill() {
598   // Only attempt to kill once.
599   if (killed_)
600     return;
601   killed_ = true;
602 
603   // We might get here even if the process we spawned has already exited. This
604   // could happen when our child process spawned another process which
605   // inherited (one of) the stdio pipes. In this case we won't attempt to send
606   // a signal to the process, however we will still close our end of the stdio
607   // pipes so this situation won't make us hang.
608   if (exit_status_ < 0) {
609     int r = uv_process_kill(&uv_process_, kill_signal_);
610 
611     // If uv_kill failed with an error that isn't ESRCH, the user probably
612     // specified an invalid or unsupported signal. Signal this to the user as
613     // and error and kill the process with SIGKILL instead.
614     if (r < 0 && r != UV_ESRCH) {
615       SetError(r);
616 
617       // Deliberately ignore the return value, we might not have
618       // sufficient privileges to signal the child process.
619       USE(uv_process_kill(&uv_process_, SIGKILL));
620     }
621   }
622 
623   // Close all stdio pipes.
624   CloseStdioPipes();
625 
626   // Stop the timeout timer immediately.
627   CloseKillTimer();
628 }
629 
630 
IncrementBufferSizeAndCheckOverflow(ssize_t length)631 void SyncProcessRunner::IncrementBufferSizeAndCheckOverflow(ssize_t length) {
632   buffered_output_size_ += length;
633 
634   if (max_buffer_ > 0 && buffered_output_size_ > max_buffer_) {
635     SetError(UV_ENOBUFS);
636     Kill();
637   }
638 }
639 
640 
OnExit(int64_t exit_status,int term_signal)641 void SyncProcessRunner::OnExit(int64_t exit_status, int term_signal) {
642   if (exit_status < 0)
643     return SetError(static_cast<int>(exit_status));
644 
645   exit_status_ = exit_status;
646   term_signal_ = term_signal;
647 }
648 
649 
OnKillTimerTimeout()650 void SyncProcessRunner::OnKillTimerTimeout() {
651   SetError(UV_ETIMEDOUT);
652   Kill();
653 }
654 
655 
GetError()656 int SyncProcessRunner::GetError() {
657   if (error_ != 0)
658     return error_;
659   else
660     return pipe_error_;
661 }
662 
663 
SetError(int error)664 void SyncProcessRunner::SetError(int error) {
665   if (error_ == 0)
666     error_ = error;
667 }
668 
669 
SetPipeError(int pipe_error)670 void SyncProcessRunner::SetPipeError(int pipe_error) {
671   if (pipe_error_ == 0)
672     pipe_error_ = pipe_error;
673 }
674 
675 
BuildResultObject()676 Local<Object> SyncProcessRunner::BuildResultObject() {
677   EscapableHandleScope scope(env()->isolate());
678   Local<Context> context = env()->context();
679 
680   Local<Object> js_result = Object::New(env()->isolate());
681 
682   if (GetError() != 0) {
683     js_result->Set(context, env()->error_string(),
684                    Integer::New(env()->isolate(), GetError())).Check();
685   }
686 
687   if (exit_status_ >= 0) {
688     if (term_signal_ > 0) {
689       js_result->Set(context, env()->status_string(),
690                      Null(env()->isolate())).Check();
691     } else {
692       js_result->Set(context, env()->status_string(),
693                      Number::New(env()->isolate(),
694                                  static_cast<double>(exit_status_))).Check();
695     }
696   } else {
697     // If exit_status_ < 0 the process was never started because of some error.
698     js_result->Set(context, env()->status_string(),
699                    Null(env()->isolate())).Check();
700   }
701 
702   if (term_signal_ > 0)
703     js_result->Set(context, env()->signal_string(),
704                    String::NewFromUtf8(env()->isolate(),
705                                        signo_string(term_signal_))
706                        .ToLocalChecked())
707         .Check();
708   else
709     js_result->Set(context, env()->signal_string(),
710                    Null(env()->isolate())).Check();
711 
712   if (exit_status_ >= 0)
713     js_result->Set(context, env()->output_string(),
714                    BuildOutputArray()).Check();
715   else
716     js_result->Set(context, env()->output_string(),
717                    Null(env()->isolate())).Check();
718 
719   js_result->Set(context, env()->pid_string(),
720                  Number::New(env()->isolate(), uv_process_.pid)).Check();
721 
722   return scope.Escape(js_result);
723 }
724 
725 
BuildOutputArray()726 Local<Array> SyncProcessRunner::BuildOutputArray() {
727   CHECK_GE(lifecycle_, kInitialized);
728   CHECK(!stdio_pipes_.empty());
729 
730   EscapableHandleScope scope(env()->isolate());
731   MaybeStackBuffer<Local<Value>, 8> js_output(stdio_pipes_.size());
732 
733   for (uint32_t i = 0; i < stdio_pipes_.size(); i++) {
734     SyncProcessStdioPipe* h = stdio_pipes_[i].get();
735     if (h != nullptr && h->writable())
736       js_output[i] = h->GetOutputAsBuffer(env());
737     else
738       js_output[i] = Null(env()->isolate());
739   }
740 
741   return scope.Escape(
742       Array::New(env()->isolate(), js_output.out(), js_output.length()));
743 }
744 
ParseOptions(Local<Value> js_value)745 Maybe<int> SyncProcessRunner::ParseOptions(Local<Value> js_value) {
746   Isolate* isolate = env()->isolate();
747   HandleScope scope(isolate);
748   int r;
749 
750   if (!js_value->IsObject()) return Just<int>(UV_EINVAL);
751 
752   Local<Context> context = env()->context();
753   Local<Object> js_options = js_value.As<Object>();
754 
755   Local<Value> js_file =
756       js_options->Get(context, env()->file_string()).ToLocalChecked();
757   if (!CopyJsString(js_file, &file_buffer_).To(&r)) return Nothing<int>();
758   if (r < 0) return Just(r);
759   uv_process_options_.file = file_buffer_;
760 
761   Local<Value> js_args =
762       js_options->Get(context, env()->args_string()).ToLocalChecked();
763   if (!CopyJsStringArray(js_args, &args_buffer_).To(&r)) return Nothing<int>();
764   if (r < 0) return Just(r);
765   uv_process_options_.args = reinterpret_cast<char**>(args_buffer_);
766 
767   Local<Value> js_cwd =
768       js_options->Get(context, env()->cwd_string()).ToLocalChecked();
769   if (IsSet(js_cwd)) {
770     if (!CopyJsString(js_cwd, &cwd_buffer_).To(&r)) return Nothing<int>();
771     if (r < 0) return Just(r);
772     uv_process_options_.cwd = cwd_buffer_;
773   }
774 
775   Local<Value> js_env_pairs =
776       js_options->Get(context, env()->env_pairs_string()).ToLocalChecked();
777   if (IsSet(js_env_pairs)) {
778     if (!CopyJsStringArray(js_env_pairs, &env_buffer_).To(&r))
779       return Nothing<int>();
780     if (r < 0) return Just(r);
781 
782     uv_process_options_.env = reinterpret_cast<char**>(env_buffer_);
783   }
784   Local<Value> js_uid =
785       js_options->Get(context, env()->uid_string()).ToLocalChecked();
786   if (IsSet(js_uid)) {
787     CHECK(js_uid->IsInt32());
788     const int32_t uid = js_uid.As<Int32>()->Value();
789     uv_process_options_.uid = static_cast<uv_uid_t>(uid);
790     uv_process_options_.flags |= UV_PROCESS_SETUID;
791   }
792 
793   Local<Value> js_gid =
794       js_options->Get(context, env()->gid_string()).ToLocalChecked();
795   if (IsSet(js_gid)) {
796     CHECK(js_gid->IsInt32());
797     const int32_t gid = js_gid.As<Int32>()->Value();
798     uv_process_options_.gid = static_cast<uv_gid_t>(gid);
799     uv_process_options_.flags |= UV_PROCESS_SETGID;
800   }
801 
802   Local<Value> js_detached =
803       js_options->Get(context, env()->detached_string()).ToLocalChecked();
804   if (js_detached->BooleanValue(isolate))
805     uv_process_options_.flags |= UV_PROCESS_DETACHED;
806 
807   Local<Value> js_win_hide =
808       js_options->Get(context, env()->windows_hide_string()).ToLocalChecked();
809   if (js_win_hide->BooleanValue(isolate))
810     uv_process_options_.flags |= UV_PROCESS_WINDOWS_HIDE;
811 
812   if (env()->hide_console_windows())
813     uv_process_options_.flags |= UV_PROCESS_WINDOWS_HIDE_CONSOLE;
814 
815   Local<Value> js_wva =
816       js_options->Get(context, env()->windows_verbatim_arguments_string())
817           .ToLocalChecked();
818 
819   if (js_wva->BooleanValue(isolate))
820     uv_process_options_.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
821 
822   Local<Value> js_timeout =
823       js_options->Get(context, env()->timeout_string()).ToLocalChecked();
824   if (IsSet(js_timeout)) {
825     CHECK(js_timeout->IsNumber());
826     int64_t timeout = js_timeout->IntegerValue(context).FromJust();
827     timeout_ = static_cast<uint64_t>(timeout);
828   }
829 
830   Local<Value> js_max_buffer =
831       js_options->Get(context, env()->max_buffer_string()).ToLocalChecked();
832   if (IsSet(js_max_buffer)) {
833     CHECK(js_max_buffer->IsNumber());
834     max_buffer_ = js_max_buffer->NumberValue(context).FromJust();
835   }
836 
837   Local<Value> js_kill_signal =
838       js_options->Get(context, env()->kill_signal_string()).ToLocalChecked();
839   if (IsSet(js_kill_signal)) {
840     CHECK(js_kill_signal->IsInt32());
841     kill_signal_ = js_kill_signal.As<Int32>()->Value();
842   }
843 
844   Local<Value> js_stdio =
845       js_options->Get(context, env()->stdio_string()).ToLocalChecked();
846   r = ParseStdioOptions(js_stdio);
847   if (r < 0) return Just(r);
848 
849   return Just(0);
850 }
851 
852 
ParseStdioOptions(Local<Value> js_value)853 int SyncProcessRunner::ParseStdioOptions(Local<Value> js_value) {
854   HandleScope scope(env()->isolate());
855   Local<Array> js_stdio_options;
856 
857   if (!js_value->IsArray())
858     return UV_EINVAL;
859 
860   Local<Context> context = env()->context();
861   js_stdio_options = js_value.As<Array>();
862 
863   stdio_count_ = js_stdio_options->Length();
864   uv_stdio_containers_ = new uv_stdio_container_t[stdio_count_];
865 
866   stdio_pipes_.clear();
867   stdio_pipes_.resize(stdio_count_);
868   stdio_pipes_initialized_ = true;
869 
870   for (uint32_t i = 0; i < stdio_count_; i++) {
871     Local<Value> js_stdio_option =
872         js_stdio_options->Get(context, i).ToLocalChecked();
873 
874     if (!js_stdio_option->IsObject())
875       return UV_EINVAL;
876 
877     int r = ParseStdioOption(i, js_stdio_option.As<Object>());
878     if (r < 0)
879       return r;
880   }
881 
882   uv_process_options_.stdio = uv_stdio_containers_;
883   uv_process_options_.stdio_count = stdio_count_;
884 
885   return 0;
886 }
887 
888 
ParseStdioOption(int child_fd,Local<Object> js_stdio_option)889 int SyncProcessRunner::ParseStdioOption(int child_fd,
890                                         Local<Object> js_stdio_option) {
891   Local<Context> context = env()->context();
892   Local<Value> js_type =
893       js_stdio_option->Get(context, env()->type_string()).ToLocalChecked();
894 
895   if (js_type->StrictEquals(env()->ignore_string())) {
896     return AddStdioIgnore(child_fd);
897 
898   } else if (js_type->StrictEquals(env()->pipe_string())) {
899     Isolate* isolate = env()->isolate();
900     Local<String> rs = env()->readable_string();
901     Local<String> ws = env()->writable_string();
902 
903     bool readable = js_stdio_option->Get(context, rs)
904         .ToLocalChecked()->BooleanValue(isolate);
905     bool writable =
906         js_stdio_option->Get(context, ws)
907         .ToLocalChecked()->BooleanValue(isolate);
908 
909     uv_buf_t buf = uv_buf_init(nullptr, 0);
910 
911     if (readable) {
912       Local<Value> input =
913           js_stdio_option->Get(context, env()->input_string()).ToLocalChecked();
914       if (Buffer::HasInstance(input)) {
915         buf = uv_buf_init(Buffer::Data(input),
916                           static_cast<unsigned int>(Buffer::Length(input)));
917       } else if (!input->IsUndefined() && !input->IsNull()) {
918         // Strings, numbers etc. are currently unsupported. It's not possible
919         // to create a buffer for them here because there is no way to free
920         // them afterwards.
921         return UV_EINVAL;
922       }
923     }
924 
925     return AddStdioPipe(child_fd, readable, writable, buf);
926 
927   } else if (js_type->StrictEquals(env()->inherit_string()) ||
928              js_type->StrictEquals(env()->fd_string())) {
929     int inherit_fd = js_stdio_option->Get(context, env()->fd_string())
930         .ToLocalChecked()->Int32Value(context).FromJust();
931     return AddStdioInheritFD(child_fd, inherit_fd);
932 
933   } else {
934     UNREACHABLE("invalid child stdio type");
935   }
936 }
937 
938 
AddStdioIgnore(uint32_t child_fd)939 int SyncProcessRunner::AddStdioIgnore(uint32_t child_fd) {
940   CHECK_LT(child_fd, stdio_count_);
941   CHECK(!stdio_pipes_[child_fd]);
942 
943   uv_stdio_containers_[child_fd].flags = UV_IGNORE;
944 
945   return 0;
946 }
947 
948 
AddStdioPipe(uint32_t child_fd,bool readable,bool writable,uv_buf_t input_buffer)949 int SyncProcessRunner::AddStdioPipe(uint32_t child_fd,
950                                     bool readable,
951                                     bool writable,
952                                     uv_buf_t input_buffer) {
953   CHECK_LT(child_fd, stdio_count_);
954   CHECK(!stdio_pipes_[child_fd]);
955 
956   std::unique_ptr<SyncProcessStdioPipe> h(
957       new SyncProcessStdioPipe(this, readable, writable, input_buffer));
958 
959   int r = h->Initialize(uv_loop_);
960   if (r < 0) {
961     h.reset();
962     return r;
963   }
964 
965   uv_stdio_containers_[child_fd].flags = h->uv_flags();
966   uv_stdio_containers_[child_fd].data.stream = h->uv_stream();
967 
968   stdio_pipes_[child_fd] = std::move(h);
969 
970   return 0;
971 }
972 
973 
AddStdioInheritFD(uint32_t child_fd,int inherit_fd)974 int SyncProcessRunner::AddStdioInheritFD(uint32_t child_fd, int inherit_fd) {
975   CHECK_LT(child_fd, stdio_count_);
976   CHECK(!stdio_pipes_[child_fd]);
977 
978   uv_stdio_containers_[child_fd].flags = UV_INHERIT_FD;
979   uv_stdio_containers_[child_fd].data.fd = inherit_fd;
980 
981   return 0;
982 }
983 
984 
IsSet(Local<Value> value)985 bool SyncProcessRunner::IsSet(Local<Value> value) {
986   return !value->IsUndefined() && !value->IsNull();
987 }
988 
CopyJsString(Local<Value> js_value,const char ** target)989 Maybe<int> SyncProcessRunner::CopyJsString(Local<Value> js_value,
990                                            const char** target) {
991   Isolate* isolate = env()->isolate();
992   Local<String> js_string;
993   size_t size, written;
994   char* buffer;
995 
996   if (js_value->IsString())
997     js_string = js_value.As<String>();
998   else if (!js_value->ToString(env()->isolate()->GetCurrentContext())
999                 .ToLocal(&js_string))
1000     return Nothing<int>();
1001 
1002   // Include space for null terminator byte.
1003   if (!StringBytes::StorageSize(isolate, js_string, UTF8).To(&size))
1004     return Nothing<int>();
1005   size += 1;
1006 
1007   buffer = new char[size];
1008 
1009   written = StringBytes::Write(isolate, buffer, -1, js_string, UTF8);
1010   buffer[written] = '\0';
1011 
1012   *target = buffer;
1013   return Just(0);
1014 }
1015 
CopyJsStringArray(Local<Value> js_value,char ** target)1016 Maybe<int> SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
1017                                                 char** target) {
1018   Isolate* isolate = env()->isolate();
1019   Local<Array> js_array;
1020   uint32_t length;
1021   size_t list_size, data_size, data_offset;
1022   char** list;
1023   char* buffer;
1024 
1025   if (!js_value->IsArray()) return Just<int>(UV_EINVAL);
1026 
1027   Local<Context> context = env()->context();
1028   js_array = js_value.As<Array>()->Clone().As<Array>();
1029   length = js_array->Length();
1030   data_size = 0;
1031 
1032   // Index has a pointer to every string element, plus one more for a final
1033   // null pointer.
1034   list_size = (length + 1) * sizeof *list;
1035 
1036   // Convert all array elements to string. Modify the js object itself if
1037   // needed - it's okay since we cloned the original object. Also compute the
1038   // length of all strings, including room for a null terminator after every
1039   // string. Align strings to cache lines.
1040   for (uint32_t i = 0; i < length; i++) {
1041     auto value = js_array->Get(context, i).ToLocalChecked();
1042 
1043     if (!value->IsString()) {
1044       Local<String> string;
1045       if (!value->ToString(env()->isolate()->GetCurrentContext())
1046                .ToLocal(&string))
1047         return Nothing<int>();
1048       js_array
1049           ->Set(context,
1050                 i,
1051                 string)
1052           .Check();
1053     }
1054 
1055     Maybe<size_t> maybe_size = StringBytes::StorageSize(isolate, value, UTF8);
1056     if (maybe_size.IsNothing()) return Nothing<int>();
1057     data_size += maybe_size.FromJust() + 1;
1058     data_size = RoundUp(data_size, sizeof(void*));
1059   }
1060 
1061   buffer = new char[list_size + data_size];
1062 
1063   list = reinterpret_cast<char**>(buffer);
1064   data_offset = list_size;
1065 
1066   for (uint32_t i = 0; i < length; i++) {
1067     list[i] = buffer + data_offset;
1068     auto value = js_array->Get(context, i).ToLocalChecked();
1069     data_offset += StringBytes::Write(isolate,
1070                                       buffer + data_offset,
1071                                       -1,
1072                                       value,
1073                                       UTF8);
1074     buffer[data_offset++] = '\0';
1075     data_offset = RoundUp(data_offset, sizeof(void*));
1076   }
1077 
1078   list[length] = nullptr;
1079 
1080   *target = buffer;
1081   return Just(0);
1082 }
1083 
1084 
ExitCallback(uv_process_t * handle,int64_t exit_status,int term_signal)1085 void SyncProcessRunner::ExitCallback(uv_process_t* handle,
1086                                      int64_t exit_status,
1087                                      int term_signal) {
1088   SyncProcessRunner* self = reinterpret_cast<SyncProcessRunner*>(handle->data);
1089   uv_close(reinterpret_cast<uv_handle_t*>(handle), nullptr);
1090   self->OnExit(exit_status, term_signal);
1091 }
1092 
1093 
KillTimerCallback(uv_timer_t * handle)1094 void SyncProcessRunner::KillTimerCallback(uv_timer_t* handle) {
1095   SyncProcessRunner* self = reinterpret_cast<SyncProcessRunner*>(handle->data);
1096   self->OnKillTimerTimeout();
1097 }
1098 
1099 
KillTimerCloseCallback(uv_handle_t * handle)1100 void SyncProcessRunner::KillTimerCloseCallback(uv_handle_t* handle) {
1101   // No-op.
1102 }
1103 
1104 }  // namespace node
1105 
1106 NODE_BINDING_CONTEXT_AWARE_INTERNAL(spawn_sync,
1107                                     node::SyncProcessRunner::Initialize)
1108