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

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

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

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

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

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

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

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

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


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

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