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: 485 531 91.3 %
Date: 2019-02-23 22:23:05 Branches: 208 322 64.6 %

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 <string.h>
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
53
9640
SyncProcessOutputBuffer::SyncProcessOutputBuffer() {
54
9640
}
55
56
57
122461
void SyncProcessOutputBuffer::OnAlloc(size_t suggested_size,
58
                                      uv_buf_t* buf) const {
59
122461
  if (used() == kBufferSize)
60
    *buf = uv_buf_init(nullptr, 0);
61
  else
62
122461
    *buf = uv_buf_init(data_ + used(), available());
63
122461
}
64
65
66
119743
void SyncProcessOutputBuffer::OnRead(const uv_buf_t* buf, size_t nread) {
67
  // If we hand out the same chunk twice, this should catch it.
68
119743
  CHECK_EQ(buf->base, data_ + used());
69
119743
  used_ += static_cast<unsigned int>(nread);
70
119743
}
71
72
73
9640
size_t SyncProcessOutputBuffer::Copy(char* dest) const {
74
9640
  memcpy(dest, data_, used());
75
9640
  return used();
76
}
77
78
79
242173
unsigned int SyncProcessOutputBuffer::available() const {
80
242173
  return sizeof data_ - used();
81
}
82
83
84
635758
unsigned int SyncProcessOutputBuffer::used() const {
85
635758
  return used_;
86
}
87
88
89
28920
SyncProcessOutputBuffer* SyncProcessOutputBuffer::next() const {
90
28920
  return next_;
91
}
92
93
94
6891
void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) {
95
6891
  next_ = next;
96
6891
}
97
98
99
5865
SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler,
100
                                           bool readable,
101
                                           bool writable,
102
                                           uv_buf_t input_buffer)
103
    : process_handler_(process_handler),
104
      readable_(readable),
105
      writable_(writable),
106
      input_buffer_(input_buffer),
107
108
      first_output_buffer_(nullptr),
109
      last_output_buffer_(nullptr),
110
111
      uv_pipe_(),
112
      write_req_(),
113
      shutdown_req_(),
114
115
5865
      lifecycle_(kUninitialized) {
116

5865
  CHECK(readable || writable);
117
5865
}
118
119
120
5865
SyncProcessStdioPipe::~SyncProcessStdioPipe() {
121

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

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

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

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

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

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

3848
      } else if (!input->IsUndefined() && !input->IsNull()) {
912
        // Strings, numbers etc. are currently unsupported. It's not possible
913
        // to create a buffer for them here because there is no way to free
914
        // them afterwards.
915
        return UV_EINVAL;
916
      }
917
    }
918
919
5865
    return AddStdioPipe(child_fd, readable, writable, buf);
920
921


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

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