GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/spawn_sync.cc Lines: 483 529 91.3 %
Date: 2019-05-05 22:32:45 Branches: 207 322 64.3 %

Line Branch Exec Source
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.h"
24
#include "env-inl.h"
25
#include "node_internals.h"
26
#include "string_bytes.h"
27
28
#include <cstring>
29
30
31
namespace node {
32
33
using v8::Array;
34
using v8::Context;
35
using v8::EscapableHandleScope;
36
using v8::FunctionCallbackInfo;
37
using v8::HandleScope;
38
using v8::Int32;
39
using v8::Integer;
40
using v8::Isolate;
41
using v8::Just;
42
using v8::Local;
43
using v8::Maybe;
44
using v8::MaybeLocal;
45
using v8::Nothing;
46
using v8::Null;
47
using v8::Number;
48
using v8::Object;
49
using v8::String;
50
using v8::Value;
51
52
84243
void SyncProcessOutputBuffer::OnAlloc(size_t suggested_size,
53
                                      uv_buf_t* buf) const {
54
84243
  if (used() == kBufferSize)
55
    *buf = uv_buf_init(nullptr, 0);
56
  else
57
84243
    *buf = uv_buf_init(data_ + used(), available());
58
84243
}
59
60
61
79306
void SyncProcessOutputBuffer::OnRead(const uv_buf_t* buf, size_t nread) {
62
  // If we hand out the same chunk twice, this should catch it.
63
79306
  CHECK_EQ(buf->base, data_ + used());
64
79306
  used_ += static_cast<unsigned int>(nread);
65
79306
}
66
67
68
8741
size_t SyncProcessOutputBuffer::Copy(char* dest) const {
69
8741
  memcpy(dest, data_, used());
70
8741
  return used();
71
}
72
73
74
163314
unsigned int SyncProcessOutputBuffer::available() const {
75
163314
  return sizeof data_ - used();
76
}
77
78
79
437329
unsigned int SyncProcessOutputBuffer::used() const {
80
437329
  return used_;
81
}
82
83
84
26223
SyncProcessOutputBuffer* SyncProcessOutputBuffer::next() const {
85
26223
  return next_;
86
}
87
88
89
3569
void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) {
90
3569
  next_ = next;
91
3569
}
92
93
94
9777
SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler,
95
                                           bool readable,
96
                                           bool writable,
97
                                           uv_buf_t input_buffer)
98
    : process_handler_(process_handler),
99
      readable_(readable),
100
      writable_(writable),
101
      input_buffer_(input_buffer),
102
103
      first_output_buffer_(nullptr),
104
      last_output_buffer_(nullptr),
105
106
      uv_pipe_(),
107
      write_req_(),
108
      shutdown_req_(),
109
110
9777
      lifecycle_(kUninitialized) {
111

9777
  CHECK(readable || writable);
112
9777
}
113
114
115
9777
SyncProcessStdioPipe::~SyncProcessStdioPipe() {
116

9777
  CHECK(lifecycle_ == kUninitialized || lifecycle_ == kClosed);
117
118
  SyncProcessOutputBuffer* buf;
119
  SyncProcessOutputBuffer* next;
120
121
18518
  for (buf = first_output_buffer_; buf != nullptr; buf = next) {
122
8741
    next = buf->next();
123
8741
    delete buf;
124
  }
125
9777
}
126
127
128
9777
int SyncProcessStdioPipe::Initialize(uv_loop_t* loop) {
129
9777
  CHECK_EQ(lifecycle_, kUninitialized);
130
131
9777
  int r = uv_pipe_init(loop, uv_pipe(), 0);
132
9777
  if (r < 0)
133
    return r;
134
135
9777
  uv_pipe()->data = this;
136
137
9777
  lifecycle_ = kInitialized;
138
9777
  return 0;
139
}
140
141
142
7995
int SyncProcessStdioPipe::Start() {
143
7995
  CHECK_EQ(lifecycle_, kInitialized);
144
145
  // Set the busy flag already. If this function fails no recovery is
146
  // possible.
147
7995
  lifecycle_ = kStarted;
148
149
7995
  if (readable()) {
150
2651
    if (input_buffer_.len > 0) {
151
21
      CHECK_NOT_NULL(input_buffer_.base);
152
153
      int r = uv_write(&write_req_,
154
                       uv_stream(),
155
                       &input_buffer_,
156
                       1,
157
21
                       WriteCallback);
158
21
      if (r < 0)
159
        return r;
160
    }
161
162
2651
    int r = uv_shutdown(&shutdown_req_, uv_stream(), ShutdownCallback);
163
2651
    if (r < 0)
164
      return r;
165
  }
166
167
7995
  if (writable()) {
168
5344
    int r = uv_read_start(uv_stream(), AllocCallback, ReadCallback);
169
5344
    if (r < 0)
170
      return r;
171
  }
172
173
7995
  return 0;
174
}
175
176
177
9777
void SyncProcessStdioPipe::Close() {
178

9777
  CHECK(lifecycle_ == kInitialized || lifecycle_ == kStarted);
179
180
9777
  uv_close(uv_handle(), CloseCallback);
181
182
9777
  lifecycle_ = kClosing;
183
9777
}
184
185
186
5344
Local<Object> SyncProcessStdioPipe::GetOutputAsBuffer(Environment* env) const {
187
5344
  size_t length = OutputLength();
188
10688
  Local<Object> js_buffer = Buffer::New(env, length).ToLocalChecked();
189
5344
  CopyOutput(Buffer::Data(js_buffer));
190
5344
  return js_buffer;
191
}
192
193
194
17772
bool SyncProcessStdioPipe::readable() const {
195
17772
  return readable_;
196
}
197
198
199
25767
bool SyncProcessStdioPipe::writable() const {
200
25767
  return writable_;
201
}
202
203
204
9777
uv_stdio_flags SyncProcessStdioPipe::uv_flags() const {
205
  unsigned int flags;
206
207
9777
  flags = UV_CREATE_PIPE;
208
9777
  if (readable())
209
3245
    flags |= UV_READABLE_PIPE;
210
9777
  if (writable())
211
6532
    flags |= UV_WRITABLE_PIPE;
212
213
9777
  return static_cast<uv_stdio_flags>(flags);
214
}
215
216
217
47124
uv_pipe_t* SyncProcessStdioPipe::uv_pipe() const {
218
47124
  CHECK_LT(lifecycle_, kClosing);
219
47124
  return &uv_pipe_;
220
}
221
222
223
17793
uv_stream_t* SyncProcessStdioPipe::uv_stream() const {
224
17793
  return reinterpret_cast<uv_stream_t*>(uv_pipe());
225
}
226
227
228
9777
uv_handle_t* SyncProcessStdioPipe::uv_handle() const {
229
9777
  return reinterpret_cast<uv_handle_t*>(uv_pipe());
230
}
231
232
233
5344
size_t SyncProcessStdioPipe::OutputLength() const {
234
  SyncProcessOutputBuffer* buf;
235
5344
  size_t size = 0;
236
237
14085
  for (buf = first_output_buffer_; buf != nullptr; buf = buf->next())
238
8741
    size += buf->used();
239
240
5344
  return size;
241
}
242
243
244
5344
void SyncProcessStdioPipe::CopyOutput(char* dest) const {
245
  SyncProcessOutputBuffer* buf;
246
5344
  size_t offset = 0;
247
248
14085
  for (buf = first_output_buffer_; buf != nullptr; buf = buf->next())
249
8741
    offset += buf->Copy(dest + offset);
250
5344
}
251
252
253
84243
void SyncProcessStdioPipe::OnAlloc(size_t suggested_size, uv_buf_t* buf) {
254
  // This function assumes that libuv will never allocate two buffers for the
255
  // same stream at the same time. There's an assert in
256
  // SyncProcessOutputBuffer::OnRead that would fail if this assumption was
257
  // ever violated.
258
259
84243
  if (last_output_buffer_ == nullptr) {
260
    // Allocate the first capture buffer.
261
5172
    first_output_buffer_ = new SyncProcessOutputBuffer();
262
5172
    last_output_buffer_ = first_output_buffer_;
263
264
79071
  } else if (last_output_buffer_->available() == 0) {
265
    // The current capture buffer is full so get us a new one.
266
3569
    SyncProcessOutputBuffer* buf = new SyncProcessOutputBuffer();
267
3569
    last_output_buffer_->set_next(buf);
268
3569
    last_output_buffer_ = buf;
269
  }
270
271
84243
  last_output_buffer_->OnAlloc(suggested_size, buf);
272
84243
}
273
274
275
84316
void SyncProcessStdioPipe::OnRead(const uv_buf_t* buf, ssize_t nread) {
276
84316
  if (nread == UV_EOF) {
277
    // Libuv implicitly stops reading on EOF.
278
279
79306
  } else if (nread < 0) {
280
    SetError(static_cast<int>(nread));
281
    // At some point libuv should really implicitly stop reading on error.
282
    uv_read_stop(uv_stream());
283
284
  } else {
285
79306
    last_output_buffer_->OnRead(buf, nread);
286
79306
    process_handler_->IncrementBufferSizeAndCheckOverflow(nread);
287
  }
288
84316
}
289
290
291
21
void SyncProcessStdioPipe::OnWriteDone(int result) {
292
21
  if (result < 0)
293
    SetError(result);
294
21
}
295
296
297
2651
void SyncProcessStdioPipe::OnShutdownDone(int result) {
298
2651
  if (result < 0)
299
    SetError(result);
300
2651
}
301
302
303
9777
void SyncProcessStdioPipe::OnClose() {
304
9777
  lifecycle_ = kClosed;
305
9777
}
306
307
308
void SyncProcessStdioPipe::SetError(int error) {
309
  CHECK_NE(error, 0);
310
  process_handler_->SetPipeError(error);
311
}
312
313
314
84243
void SyncProcessStdioPipe::AllocCallback(uv_handle_t* handle,
315
                                         size_t suggested_size,
316
                                         uv_buf_t* buf) {
317
  SyncProcessStdioPipe* self =
318
84243
      reinterpret_cast<SyncProcessStdioPipe*>(handle->data);
319
84243
  self->OnAlloc(suggested_size, buf);
320
84243
}
321
322
323
84316
void SyncProcessStdioPipe::ReadCallback(uv_stream_t* stream,
324
                                        ssize_t nread,
325
                                        const uv_buf_t* buf) {
326
  SyncProcessStdioPipe* self =
327
84316
        reinterpret_cast<SyncProcessStdioPipe*>(stream->data);
328
84316
  self->OnRead(buf, nread);
329
84316
}
330
331
332
21
void SyncProcessStdioPipe::WriteCallback(uv_write_t* req, int result) {
333
  SyncProcessStdioPipe* self =
334
21
      reinterpret_cast<SyncProcessStdioPipe*>(req->handle->data);
335
21
  self->OnWriteDone(result);
336
21
}
337
338
339
2651
void SyncProcessStdioPipe::ShutdownCallback(uv_shutdown_t* req, int result) {
340
  SyncProcessStdioPipe* self =
341
2651
      reinterpret_cast<SyncProcessStdioPipe*>(req->handle->data);
342
343
  // On AIX, OS X and the BSDs, calling shutdown() on one end of a pipe
344
  // when the other end has closed the connection fails with ENOTCONN.
345
  // Libuv is not the right place to handle that because it can't tell
346
  // if the error is genuine but we here can.
347
2651
  if (result == UV_ENOTCONN)
348
    result = 0;
349
350
2651
  self->OnShutdownDone(result);
351
2651
}
352
353
354
9777
void SyncProcessStdioPipe::CloseCallback(uv_handle_t* handle) {
355
  SyncProcessStdioPipe* self =
356
9777
      reinterpret_cast<SyncProcessStdioPipe*>(handle->data);
357
9777
  self->OnClose();
358
9777
}
359
360
361
3957
void SyncProcessRunner::Initialize(Local<Object> target,
362
                                   Local<Value> unused,
363
                                   Local<Context> context,
364
                                   void* priv) {
365
3957
  Environment* env = Environment::GetCurrent(context);
366
3957
  env->SetMethod(target, "spawn", Spawn);
367
3957
}
368
369
370
3298
void SyncProcessRunner::Spawn(const FunctionCallbackInfo<Value>& args) {
371
3298
  Environment* env = Environment::GetCurrent(args);
372
3298
  env->PrintSyncTrace();
373
3298
  SyncProcessRunner p(env);
374
  Local<Value> result;
375
9894
  if (!p.Run(args[0]).ToLocal(&result)) return;
376
6596
  args.GetReturnValue().Set(result);
377
}
378
379
380
3298
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
3298
      env_(env) {
413
3298
}
414
415
416
6596
SyncProcessRunner::~SyncProcessRunner() {
417
3298
  CHECK_EQ(lifecycle_, kHandlesClosed);
418
419
3298
  stdio_pipes_.clear();
420
3298
  delete[] file_buffer_;
421
3298
  delete[] args_buffer_;
422
3298
  delete[] cwd_buffer_;
423
3298
  delete[] env_buffer_;
424
3298
  delete[] uv_stdio_containers_;
425
3298
}
426
427
428
199439
Environment* SyncProcessRunner::env() const {
429
199439
  return env_;
430
}
431
432
3298
MaybeLocal<Object> SyncProcessRunner::Run(Local<Value> options) {
433
3298
  EscapableHandleScope scope(env()->isolate());
434
435
3298
  CHECK_EQ(lifecycle_, kUninitialized);
436
437
3298
  Maybe<bool> r = TryInitializeAndRunLoop(options);
438
3298
  CloseHandlesAndDeleteLoop();
439
3298
  if (r.IsNothing()) return MaybeLocal<Object>();
440
441
3298
  Local<Object> result = BuildResultObject();
442
443
3298
  return scope.Escape(result);
444
}
445
446
3298
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
3298
  CHECK_EQ(lifecycle_, kUninitialized);
452
3298
  lifecycle_ = kInitialized;
453
454
3298
  uv_loop_ = new uv_loop_t;
455
3298
  if (uv_loop_ == nullptr) {
456
    SetError(UV_ENOMEM);
457
    return Just(false);
458
  }
459
3298
  CHECK_EQ(uv_loop_init(uv_loop_), 0);
460
461
6596
  if (!ParseOptions(options).To(&r)) return Nothing<bool>();
462
3298
  if (r < 0) {
463
    SetError(r);
464
    return Just(false);
465
  }
466
467
3298
  if (timeout_ > 0) {
468
6
    r = uv_timer_init(uv_loop_, &uv_timer_);
469
6
    if (r < 0) {
470
      SetError(r);
471
      return Just(false);
472
    }
473
474
6
    uv_unref(reinterpret_cast<uv_handle_t*>(&uv_timer_));
475
476
6
    uv_timer_.data = this;
477
6
    kill_timer_initialized_ = true;
478
479
    // Start the timer immediately. If uv_spawn fails then
480
    // CloseHandlesAndDeleteLoop() will immediately close the timer handle
481
    // which implicitly stops it, so there is no risk that the timeout callback
482
    // runs when the process didn't start.
483
6
    r = uv_timer_start(&uv_timer_, KillTimerCallback, timeout_, 0);
484
6
    if (r < 0) {
485
      SetError(r);
486
      return Just(false);
487
    }
488
  }
489
490
3298
  uv_process_options_.exit_cb = ExitCallback;
491
3298
  r = uv_spawn(uv_loop_, &uv_process_, &uv_process_options_);
492
3298
  if (r < 0) {
493
594
    SetError(r);
494
594
    return Just(false);
495
  }
496
2704
  uv_process_.data = this;
497
498
10816
  for (const auto& pipe : stdio_pipes_) {
499
8112
    if (pipe != nullptr) {
500
7995
      r = pipe->Start();
501
7995
      if (r < 0) {
502
        SetPipeError(r);
503
        return Just(false);
504
      }
505
    }
506
  }
507
508
2704
  r = uv_run(uv_loop_, UV_RUN_DEFAULT);
509
2704
  if (r < 0)
510
    // We can't handle uv_run failure.
511
    ABORT();
512
513
  // If we get here the process should have exited.
514
2704
  CHECK_GE(exit_status_, 0);
515
2704
  return Just(true);
516
}
517
518
519
3298
void SyncProcessRunner::CloseHandlesAndDeleteLoop() {
520
3298
  CHECK_LT(lifecycle_, kHandlesClosed);
521
522
3298
  if (uv_loop_ != nullptr) {
523
3298
    CloseStdioPipes();
524
3298
    CloseKillTimer();
525
    // Close the process handle when ExitCallback was not called.
526
    uv_handle_t* uv_process_handle =
527
3298
        reinterpret_cast<uv_handle_t*>(&uv_process_);
528
529
    // Close the process handle if it is still open. The handle type also
530
    // needs to be checked because TryInitializeAndRunLoop() won't spawn a
531
    // process if input validation fails.
532

6596
    if (uv_process_handle->type == UV_PROCESS &&
533
3298
        !uv_is_closing(uv_process_handle))
534
594
      uv_close(uv_process_handle, nullptr);
535
536
    // Give closing watchers a chance to finish closing and get their close
537
    // callbacks called.
538
3298
    int r = uv_run(uv_loop_, UV_RUN_DEFAULT);
539
3298
    if (r < 0)
540
      ABORT();
541
542
3298
    CheckedUvLoopClose(uv_loop_);
543
3298
    delete uv_loop_;
544
3298
    uv_loop_ = nullptr;
545
546
  } else {
547
    // If the loop doesn't exist, neither should any pipes or timers.
548
    CHECK_EQ(false, stdio_pipes_initialized_);
549
    CHECK_EQ(false, kill_timer_initialized_);
550
  }
551
552
3298
  lifecycle_ = kHandlesClosed;
553
3298
}
554
555
556
3465
void SyncProcessRunner::CloseStdioPipes() {
557
3465
  CHECK_LT(lifecycle_, kHandlesClosed);
558
559
3465
  if (stdio_pipes_initialized_) {
560
3298
    CHECK(!stdio_pipes_.empty());
561
3298
    CHECK_NOT_NULL(uv_loop_);
562
563
13192
    for (const auto& pipe : stdio_pipes_) {
564
9894
      if (pipe)
565
9777
        pipe->Close();
566
    }
567
568
3298
    stdio_pipes_initialized_ = false;
569
  }
570
3465
}
571
572
573
3465
void SyncProcessRunner::CloseKillTimer() {
574
3465
  CHECK_LT(lifecycle_, kHandlesClosed);
575
576
3465
  if (kill_timer_initialized_) {
577
6
    CHECK_GT(timeout_, 0);
578
6
    CHECK_NOT_NULL(uv_loop_);
579
580
6
    uv_handle_t* uv_timer_handle = reinterpret_cast<uv_handle_t*>(&uv_timer_);
581
6
    uv_ref(uv_timer_handle);
582
6
    uv_close(uv_timer_handle, KillTimerCloseCallback);
583
584
6
    kill_timer_initialized_ = false;
585
  }
586
3465
}
587
588
589
167
void SyncProcessRunner::Kill() {
590
  // Only attempt to kill once.
591
167
  if (killed_)
592
167
    return;
593
167
  killed_ = true;
594
595
  // We might get here even if the process we spawned has already exited. This
596
  // could happen when our child process spawned another process which
597
  // inherited (one of) the stdio pipes. In this case we won't attempt to send
598
  // a signal to the process, however we will still close our end of the stdio
599
  // pipes so this situation won't make us hang.
600
167
  if (exit_status_ < 0) {
601
167
    int r = uv_process_kill(&uv_process_, kill_signal_);
602
603
    // If uv_kill failed with an error that isn't ESRCH, the user probably
604
    // specified an invalid or unsupported signal. Signal this to the user as
605
    // and error and kill the process with SIGKILL instead.
606

167
    if (r < 0 && r != UV_ESRCH) {
607
      SetError(r);
608
609
      r = uv_process_kill(&uv_process_, SIGKILL);
610
      CHECK(r >= 0 || r == UV_ESRCH);
611
    }
612
  }
613
614
  // Close all stdio pipes.
615
167
  CloseStdioPipes();
616
617
  // Stop the timeout timer immediately.
618
167
  CloseKillTimer();
619
}
620
621
622
79306
void SyncProcessRunner::IncrementBufferSizeAndCheckOverflow(ssize_t length) {
623
79306
  buffered_output_size_ += length;
624
625

79306
  if (max_buffer_ > 0 && buffered_output_size_ > max_buffer_) {
626
162
    SetError(UV_ENOBUFS);
627
162
    Kill();
628
  }
629
79306
}
630
631
632
2704
void SyncProcessRunner::OnExit(int64_t exit_status, int term_signal) {
633
2704
  if (exit_status < 0)
634
2704
    return SetError(static_cast<int>(exit_status));
635
636
2704
  exit_status_ = exit_status;
637
2704
  term_signal_ = term_signal;
638
}
639
640
641
5
void SyncProcessRunner::OnKillTimerTimeout() {
642
5
  SetError(UV_ETIMEDOUT);
643
5
  Kill();
644
5
}
645
646
647
4059
int SyncProcessRunner::GetError() {
648
4059
  if (error_ != 0)
649
1522
    return error_;
650
  else
651
2537
    return pipe_error_;
652
}
653
654
655
761
void SyncProcessRunner::SetError(int error) {
656
761
  if (error_ == 0)
657
761
    error_ = error;
658
761
}
659
660
661
void SyncProcessRunner::SetPipeError(int pipe_error) {
662
  if (pipe_error_ == 0)
663
    pipe_error_ = pipe_error;
664
}
665
666
667
3298
Local<Object> SyncProcessRunner::BuildResultObject() {
668
3298
  EscapableHandleScope scope(env()->isolate());
669
3298
  Local<Context> context = env()->context();
670
671
3298
  Local<Object> js_result = Object::New(env()->isolate());
672
673
3298
  if (GetError() != 0) {
674
    js_result->Set(context, env()->error_string(),
675
3044
                   Integer::New(env()->isolate(), GetError())).Check();
676
  }
677
678
3298
  if (exit_status_ >= 0) {
679
2704
    if (term_signal_ > 0) {
680
      js_result->Set(context, env()->status_string(),
681
696
                     Null(env()->isolate())).Check();
682
    } else {
683
      js_result->Set(context, env()->status_string(),
684
                     Number::New(env()->isolate(),
685
10120
                                 static_cast<double>(exit_status_))).Check();
686
    }
687
  } else {
688
    // If exit_status_ < 0 the process was never started because of some error.
689
    js_result->Set(context, env()->status_string(),
690
2376
                   Null(env()->isolate())).Check();
691
  }
692
693
3298
  if (term_signal_ > 0)
694
    js_result->Set(context, env()->signal_string(),
695
                   String::NewFromUtf8(env()->isolate(),
696
                                       signo_string(term_signal_),
697
174
                                       v8::NewStringType::kNormal)
698
696
                       .ToLocalChecked())
699
348
        .Check();
700
  else
701
    js_result->Set(context, env()->signal_string(),
702
12496
                   Null(env()->isolate())).Check();
703
704
3298
  if (exit_status_ >= 0)
705
    js_result->Set(context, env()->output_string(),
706
10816
                   BuildOutputArray()).Check();
707
  else
708
    js_result->Set(context, env()->output_string(),
709
2376
                   Null(env()->isolate())).Check();
710
711
  js_result->Set(context, env()->pid_string(),
712
13192
                 Number::New(env()->isolate(), uv_process_.pid)).Check();
713
714
3298
  return scope.Escape(js_result);
715
}
716
717
718
2704
Local<Array> SyncProcessRunner::BuildOutputArray() {
719
2704
  CHECK_GE(lifecycle_, kInitialized);
720
2704
  CHECK(!stdio_pipes_.empty());
721
722
2704
  EscapableHandleScope scope(env()->isolate());
723
2704
  Local<Context> context = env()->context();
724
2704
  Local<Array> js_output = Array::New(env()->isolate(), stdio_count_);
725
726
10816
  for (uint32_t i = 0; i < stdio_pipes_.size(); i++) {
727
8112
    SyncProcessStdioPipe* h = stdio_pipes_[i].get();
728

8112
    if (h != nullptr && h->writable())
729
16032
      js_output->Set(context, i, h->GetOutputAsBuffer(env())).Check();
730
    else
731
8304
      js_output->Set(context, i, Null(env()->isolate())).Check();
732
  }
733
734
2704
  return scope.Escape(js_output);
735
}
736
737
3298
Maybe<int> SyncProcessRunner::ParseOptions(Local<Value> js_value) {
738
3298
  Isolate* isolate = env()->isolate();
739
3298
  HandleScope scope(isolate);
740
  int r;
741
742
3298
  if (!js_value->IsObject()) return Just<int>(UV_EINVAL);
743
744
3298
  Local<Context> context = env()->context();
745
3298
  Local<Object> js_options = js_value.As<Object>();
746
747
  Local<Value> js_file =
748
9894
      js_options->Get(context, env()->file_string()).ToLocalChecked();
749
6596
  if (!CopyJsString(js_file, &file_buffer_).To(&r)) return Nothing<int>();
750
3298
  if (r < 0) return Just(r);
751
3298
  uv_process_options_.file = file_buffer_;
752
753
  Local<Value> js_args =
754
9894
      js_options->Get(context, env()->args_string()).ToLocalChecked();
755
6596
  if (!CopyJsStringArray(js_args, &args_buffer_).To(&r)) return Nothing<int>();
756
3298
  if (r < 0) return Just(r);
757
3298
  uv_process_options_.args = reinterpret_cast<char**>(args_buffer_);
758
759
  Local<Value> js_cwd =
760
9894
      js_options->Get(context, env()->cwd_string()).ToLocalChecked();
761
3298
  if (IsSet(js_cwd)) {
762
162
    if (!CopyJsString(js_cwd, &cwd_buffer_).To(&r)) return Nothing<int>();
763
81
    if (r < 0) return Just(r);
764
81
    uv_process_options_.cwd = cwd_buffer_;
765
  }
766
767
  Local<Value> js_env_pairs =
768
9894
      js_options->Get(context, env()->env_pairs_string()).ToLocalChecked();
769
3298
  if (IsSet(js_env_pairs)) {
770
6596
    if (!CopyJsStringArray(js_env_pairs, &env_buffer_).To(&r))
771
      return Nothing<int>();
772
3298
    if (r < 0) return Just(r);
773
774
3298
    uv_process_options_.env = reinterpret_cast<char**>(env_buffer_);
775
  }
776
  Local<Value> js_uid =
777
9894
      js_options->Get(context, env()->uid_string()).ToLocalChecked();
778
3298
  if (IsSet(js_uid)) {
779
1
    CHECK(js_uid->IsInt32());
780
2
    const int32_t uid = js_uid.As<Int32>()->Value();
781
1
    uv_process_options_.uid = static_cast<uv_uid_t>(uid);
782
1
    uv_process_options_.flags |= UV_PROCESS_SETUID;
783
  }
784
785
  Local<Value> js_gid =
786
9894
      js_options->Get(context, env()->gid_string()).ToLocalChecked();
787
3298
  if (IsSet(js_gid)) {
788
1
    CHECK(js_gid->IsInt32());
789
2
    const int32_t gid = js_gid.As<Int32>()->Value();
790
1
    uv_process_options_.gid = static_cast<uv_gid_t>(gid);
791
1
    uv_process_options_.flags |= UV_PROCESS_SETGID;
792
  }
793
794
  Local<Value> js_detached =
795
9894
      js_options->Get(context, env()->detached_string()).ToLocalChecked();
796
3298
  if (js_detached->BooleanValue(isolate))
797
1
    uv_process_options_.flags |= UV_PROCESS_DETACHED;
798
799
  Local<Value> js_win_hide =
800
9894
      js_options->Get(context, env()->windows_hide_string()).ToLocalChecked();
801
3298
  if (js_win_hide->BooleanValue(isolate))
802
2
    uv_process_options_.flags |= UV_PROCESS_WINDOWS_HIDE;
803
804
  Local<Value> js_wva =
805
9894
      js_options->Get(context, env()->windows_verbatim_arguments_string())
806
6596
          .ToLocalChecked();
807
808
3298
  if (js_wva->BooleanValue(isolate))
809
1
    uv_process_options_.flags |= UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS;
810
811
  Local<Value> js_timeout =
812
9894
      js_options->Get(context, env()->timeout_string()).ToLocalChecked();
813
3298
  if (IsSet(js_timeout)) {
814
7
    CHECK(js_timeout->IsNumber());
815
14
    int64_t timeout = js_timeout->IntegerValue(context).FromJust();
816
7
    timeout_ = static_cast<uint64_t>(timeout);
817
  }
818
819
  Local<Value> js_max_buffer =
820
9894
      js_options->Get(context, env()->max_buffer_string()).ToLocalChecked();
821
3298
  if (IsSet(js_max_buffer)) {
822
3296
    CHECK(js_max_buffer->IsNumber());
823
6592
    max_buffer_ = js_max_buffer->NumberValue(context).FromJust();
824
  }
825
826
  Local<Value> js_kill_signal =
827
9894
      js_options->Get(context, env()->kill_signal_string()).ToLocalChecked();
828
3298
  if (IsSet(js_kill_signal)) {
829
105
    CHECK(js_kill_signal->IsInt32());
830
210
    kill_signal_ = js_kill_signal.As<Int32>()->Value();
831
  }
832
833
  Local<Value> js_stdio =
834
9894
      js_options->Get(context, env()->stdio_string()).ToLocalChecked();
835
3298
  r = ParseStdioOptions(js_stdio);
836
3298
  if (r < 0) return Just(r);
837
838
3298
  return Just(0);
839
}
840
841
842
3298
int SyncProcessRunner::ParseStdioOptions(Local<Value> js_value) {
843
3298
  HandleScope scope(env()->isolate());
844
  Local<Array> js_stdio_options;
845
846
3298
  if (!js_value->IsArray())
847
    return UV_EINVAL;
848
849
3298
  Local<Context> context = env()->context();
850
3298
  js_stdio_options = js_value.As<Array>();
851
852
3298
  stdio_count_ = js_stdio_options->Length();
853
3298
  uv_stdio_containers_ = new uv_stdio_container_t[stdio_count_];
854
855
3298
  stdio_pipes_.clear();
856
3298
  stdio_pipes_.resize(stdio_count_);
857
3298
  stdio_pipes_initialized_ = true;
858
859
26384
  for (uint32_t i = 0; i < stdio_count_; i++) {
860
    Local<Value> js_stdio_option =
861
19788
        js_stdio_options->Get(context, i).ToLocalChecked();
862
863
9894
    if (!js_stdio_option->IsObject())
864
      return UV_EINVAL;
865
866
9894
    int r = ParseStdioOption(i, js_stdio_option.As<Object>());
867
9894
    if (r < 0)
868
      return r;
869
  }
870
871
3298
  uv_process_options_.stdio = uv_stdio_containers_;
872
3298
  uv_process_options_.stdio_count = stdio_count_;
873
874
3298
  return 0;
875
}
876
877
878
9894
int SyncProcessRunner::ParseStdioOption(int child_fd,
879
                                        Local<Object> js_stdio_option) {
880
9894
  Local<Context> context = env()->context();
881
  Local<Value> js_type =
882
29682
      js_stdio_option->Get(context, env()->type_string()).ToLocalChecked();
883
884
19788
  if (js_type->StrictEquals(env()->ignore_string())) {
885
83
    return AddStdioIgnore(child_fd);
886
887
19622
  } else if (js_type->StrictEquals(env()->pipe_string())) {
888
9777
    Isolate* isolate = env()->isolate();
889
9777
    Local<String> rs = env()->readable_string();
890
9777
    Local<String> ws = env()->writable_string();
891
892
19554
    bool readable = js_stdio_option->Get(context, rs)
893
29331
        .ToLocalChecked()->BooleanValue(isolate);
894
    bool writable =
895
19554
        js_stdio_option->Get(context, ws)
896
29331
        .ToLocalChecked()->BooleanValue(isolate);
897
898
9777
    uv_buf_t buf = uv_buf_init(nullptr, 0);
899
900
9777
    if (readable) {
901
      Local<Value> input =
902
9735
          js_stdio_option->Get(context, env()->input_string()).ToLocalChecked();
903
3245
      if (Buffer::HasInstance(input)) {
904
        buf = uv_buf_init(Buffer::Data(input),
905
21
                          static_cast<unsigned int>(Buffer::Length(input)));
906

6448
      } else if (!input->IsUndefined() && !input->IsNull()) {
907
        // Strings, numbers etc. are currently unsupported. It's not possible
908
        // to create a buffer for them here because there is no way to free
909
        // them afterwards.
910
        return UV_EINVAL;
911
      }
912
    }
913
914
9777
    return AddStdioPipe(child_fd, readable, writable, buf);
915
916


186
  } else if (js_type->StrictEquals(env()->inherit_string()) ||
917
84
             js_type->StrictEquals(env()->fd_string())) {
918
102
    int inherit_fd = js_stdio_option->Get(context, env()->fd_string())
919
136
        .ToLocalChecked()->Int32Value(context).FromJust();
920
34
    return AddStdioInheritFD(child_fd, inherit_fd);
921
922
  } else {
923
    CHECK(0 && "invalid child stdio type");
924
    return UV_EINVAL;
925
  }
926
}
927
928
929
83
int SyncProcessRunner::AddStdioIgnore(uint32_t child_fd) {
930
83
  CHECK_LT(child_fd, stdio_count_);
931
83
  CHECK(!stdio_pipes_[child_fd]);
932
933
83
  uv_stdio_containers_[child_fd].flags = UV_IGNORE;
934
935
83
  return 0;
936
}
937
938
939
9777
int SyncProcessRunner::AddStdioPipe(uint32_t child_fd,
940
                                    bool readable,
941
                                    bool writable,
942
                                    uv_buf_t input_buffer) {
943
9777
  CHECK_LT(child_fd, stdio_count_);
944
9777
  CHECK(!stdio_pipes_[child_fd]);
945
946
  std::unique_ptr<SyncProcessStdioPipe> h(
947
9777
      new SyncProcessStdioPipe(this, readable, writable, input_buffer));
948
949
9777
  int r = h->Initialize(uv_loop_);
950
9777
  if (r < 0) {
951
    h.reset();
952
    return r;
953
  }
954
955
9777
  uv_stdio_containers_[child_fd].flags = h->uv_flags();
956
9777
  uv_stdio_containers_[child_fd].data.stream = h->uv_stream();
957
958
9777
  stdio_pipes_[child_fd] = std::move(h);
959
960
9777
  return 0;
961
}
962
963
964
34
int SyncProcessRunner::AddStdioInheritFD(uint32_t child_fd, int inherit_fd) {
965
34
  CHECK_LT(child_fd, stdio_count_);
966
34
  CHECK(!stdio_pipes_[child_fd]);
967
968
34
  uv_stdio_containers_[child_fd].flags = UV_INHERIT_FD;
969
34
  uv_stdio_containers_[child_fd].data.fd = inherit_fd;
970
971
34
  return 0;
972
}
973
974
975
23086
bool SyncProcessRunner::IsSet(Local<Value> value) {
976

59760
  return !value->IsUndefined() && !value->IsNull();
977
}
978
979
3379
Maybe<int> SyncProcessRunner::CopyJsString(Local<Value> js_value,
980
                                           const char** target) {
981
3379
  Isolate* isolate = env()->isolate();
982
  Local<String> js_string;
983
  size_t size, written;
984
  char* buffer;
985
986
6758
  if (js_value->IsString())
987
3379
    js_string = js_value.As<String>();
988
  else if (!js_value->ToString(env()->isolate()->GetCurrentContext())
989
                .ToLocal(&js_string))
990
    return Nothing<int>();
991
992
  // Include space for null terminator byte.
993
6758
  if (!StringBytes::StorageSize(isolate, js_string, UTF8).To(&size))
994
    return Nothing<int>();
995
3379
  size += 1;
996
997
3379
  buffer = new char[size];
998
999
3379
  written = StringBytes::Write(isolate, buffer, -1, js_string, UTF8);
1000
3379
  buffer[written] = '\0';
1001
1002
3379
  *target = buffer;
1003
3379
  return Just(0);
1004
}
1005
1006
6596
Maybe<int> SyncProcessRunner::CopyJsStringArray(Local<Value> js_value,
1007
                                                char** target) {
1008
6596
  Isolate* isolate = env()->isolate();
1009
  Local<Array> js_array;
1010
  uint32_t length;
1011
  size_t list_size, data_size, data_offset;
1012
  char** list;
1013
  char* buffer;
1014
1015
6596
  if (!js_value->IsArray()) return Just<int>(UV_EINVAL);
1016
1017
6596
  Local<Context> context = env()->context();
1018
19788
  js_array = js_value.As<Array>()->Clone().As<Array>();
1019
6596
  length = js_array->Length();
1020
6596
  data_size = 0;
1021
1022
  // Index has a pointer to every string element, plus one more for a final
1023
  // null pointer.
1024
6596
  list_size = (length + 1) * sizeof *list;
1025
1026
  // Convert all array elements to string. Modify the js object itself if
1027
  // needed - it's okay since we cloned the original object. Also compute the
1028
  // length of all strings, including room for a null terminator after every
1029
  // string. Align strings to cache lines.
1030
228381
  for (uint32_t i = 0; i < length; i++) {
1031
443570
    auto value = js_array->Get(context, i).ToLocalChecked();
1032
1033
443570
    if (!value->IsString()) {
1034
      Local<String> string;
1035
44
      if (!value->ToString(env()->isolate()->GetCurrentContext())
1036
33
               .ToLocal(&string))
1037
        return Nothing<int>();
1038
      js_array
1039
11
          ->Set(context,
1040
                i,
1041
22
                value->ToString(env()->isolate()->GetCurrentContext())
1042
22
                    .ToLocalChecked())
1043
22
          .Check();
1044
    }
1045
1046
221785
    Maybe<size_t> maybe_size = StringBytes::StorageSize(isolate, value, UTF8);
1047
221785
    if (maybe_size.IsNothing()) return Nothing<int>();
1048
221785
    data_size += maybe_size.FromJust() + 1;
1049
221785
    data_size = RoundUp(data_size, sizeof(void*));
1050
  }
1051
1052
6596
  buffer = new char[list_size + data_size];
1053
1054
6596
  list = reinterpret_cast<char**>(buffer);
1055
6596
  data_offset = list_size;
1056
1057
228381
  for (uint32_t i = 0; i < length; i++) {
1058
221785
    list[i] = buffer + data_offset;
1059
443570
    auto value = js_array->Get(context, i).ToLocalChecked();
1060
    data_offset += StringBytes::Write(isolate,
1061
                                      buffer + data_offset,
1062
                                      -1,
1063
                                      value,
1064
221785
                                      UTF8);
1065
221785
    buffer[data_offset++] = '\0';
1066
221785
    data_offset = RoundUp(data_offset, sizeof(void*));
1067
  }
1068
1069
6596
  list[length] = nullptr;
1070
1071
6596
  *target = buffer;
1072
6596
  return Just(0);
1073
}
1074
1075
1076
2704
void SyncProcessRunner::ExitCallback(uv_process_t* handle,
1077
                                     int64_t exit_status,
1078
                                     int term_signal) {
1079
2704
  SyncProcessRunner* self = reinterpret_cast<SyncProcessRunner*>(handle->data);
1080
2704
  uv_close(reinterpret_cast<uv_handle_t*>(handle), nullptr);
1081
2704
  self->OnExit(exit_status, term_signal);
1082
2704
}
1083
1084
1085
5
void SyncProcessRunner::KillTimerCallback(uv_timer_t* handle) {
1086
5
  SyncProcessRunner* self = reinterpret_cast<SyncProcessRunner*>(handle->data);
1087
5
  self->OnKillTimerTimeout();
1088
5
}
1089
1090
1091
6
void SyncProcessRunner::KillTimerCloseCallback(uv_handle_t* handle) {
1092
  // No-op.
1093
6
}
1094
1095
}  // namespace node
1096
1097
4524
NODE_MODULE_CONTEXT_AWARE_INTERNAL(spawn_sync,
1098
  node::SyncProcessRunner::Initialize)