GCC Code Coverage Report
Directory: ../src/ Exec Total Coverage
File: /home/node-core-coverage/node-core-coverage/workdir/node/src/spawn_sync.cc Lines: 417 460 90.7 %
Date: 2016-07-18 Branches: 195 348 56.0 %

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