GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: spawn_sync.cc Lines: 492 544 90.4 %
Date: 2022-11-08 04:21:23 Branches: 201 306 65.7 %

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-inl.h"
24
#include "env-inl.h"
25
#include "node_internals.h"
26
#include "string_bytes.h"
27
#include "util-inl.h"
28
29
#include <cstring>
30
31
32
namespace node {
33
34
using v8::Array;
35
using v8::Context;
36
using v8::EscapableHandleScope;
37
using v8::FunctionCallbackInfo;
38
using v8::HandleScope;
39
using v8::Int32;
40
using v8::Integer;
41
using v8::Isolate;
42
using v8::Just;
43
using v8::Local;
44
using v8::Maybe;
45
using v8::MaybeLocal;
46
using v8::Nothing;
47
using v8::Null;
48
using v8::Number;
49
using v8::Object;
50
using v8::String;
51
using v8::Value;
52
53
222017
void SyncProcessOutputBuffer::OnAlloc(size_t suggested_size,
54
                                      uv_buf_t* buf) const {
55
222017
  if (used() == kBufferSize)
56
    *buf = uv_buf_init(nullptr, 0);
57
  else
58
222017
    *buf = uv_buf_init(data_ + used(), available());
59
222017
}
60
61
62
220381
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
220381
  CHECK_EQ(buf->base, data_ + used());
65
220381
  used_ += static_cast<unsigned int>(nread);
66
220381
}
67
68
69
1904
size_t SyncProcessOutputBuffer::Copy(char* dest) const {
70
1904
  memcpy(dest, data_, used());
71
1904
  return used();
72
}
73
74
75
442376
unsigned int SyncProcessOutputBuffer::available() const {
76
442376
  return sizeof data_ - used();
77
}
78
79
80
1112503
unsigned int SyncProcessOutputBuffer::used() const {
81
1112503
  return used_;
82
}
83
84
85
5712
SyncProcessOutputBuffer* SyncProcessOutputBuffer::next() const {
86
5712
  return next_;
87
}
88
89
90
246
void SyncProcessOutputBuffer::set_next(SyncProcessOutputBuffer* next) {
91
246
  next_ = next;
92
246
}
93
94
95
2929
SyncProcessStdioPipe::SyncProcessStdioPipe(SyncProcessRunner* process_handler,
96
                                           bool readable,
97
                                           bool writable,
98
2929
                                           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
2929
      lifecycle_(kUninitialized) {
112

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

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

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

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

13
    if (r < 0 && r != UV_ESRCH) {
615
      SetError(r);
616
617
      // Deliberately ignore the return value, we might not have
618
      // sufficient privileges to signal the child process.
619
      USE(uv_process_kill(&uv_process_, SIGKILL));
620
    }
621
  }
622
623
  // Close all stdio pipes.
624
13
  CloseStdioPipes();
625
626
  // Stop the timeout timer immediately.
627
13
  CloseKillTimer();
628
}
629
630
631
220381
void SyncProcessRunner::IncrementBufferSizeAndCheckOverflow(ssize_t length) {
632
220381
  buffered_output_size_ += length;
633
634

220381
  if (max_buffer_ > 0 && buffered_output_size_ > max_buffer_) {
635
8
    SetError(UV_ENOBUFS);
636
8
    Kill();
637
  }
638
220381
}
639
640
641
863
void SyncProcessRunner::OnExit(int64_t exit_status, int term_signal) {
642
863
  if (exit_status < 0)
643
    return SetError(static_cast<int>(exit_status));
644
645
863
  exit_status_ = exit_status;
646
863
  term_signal_ = term_signal;
647
}
648
649
650
5
void SyncProcessRunner::OnKillTimerTimeout() {
651
5
  SetError(UV_ETIMEDOUT);
652
5
  Kill();
653
5
}
654
655
656
1160
int SyncProcessRunner::GetError() {
657
1160
  if (error_ != 0)
658
310
    return error_;
659
  else
660
850
    return pipe_error_;
661
}
662
663
664
155
void SyncProcessRunner::SetError(int error) {
665
155
  if (error_ == 0)
666
155
    error_ = error;
667
155
}
668
669
670
void SyncProcessRunner::SetPipeError(int pipe_error) {
671
  if (pipe_error_ == 0)
672
    pipe_error_ = pipe_error;
673
}
674
675
676
1005
Local<Object> SyncProcessRunner::BuildResultObject() {
677
1005
  EscapableHandleScope scope(env()->isolate());
678
1005
  Local<Context> context = env()->context();
679
680
1005
  Local<Object> js_result = Object::New(env()->isolate());
681
682
1005
  if (GetError() != 0) {
683
155
    js_result->Set(context, env()->error_string(),
684
620
                   Integer::New(env()->isolate(), GetError())).Check();
685
  }
686
687
1005
  if (exit_status_ >= 0) {
688
863
    if (term_signal_ > 0) {
689
51
      js_result->Set(context, env()->status_string(),
690
204
                     Null(env()->isolate())).Check();
691
    } else {
692
812
      js_result->Set(context, env()->status_string(),
693
                     Number::New(env()->isolate(),
694
3248
                                 static_cast<double>(exit_status_))).Check();
695
    }
696
  } else {
697
    // If exit_status_ < 0 the process was never started because of some error.
698
142
    js_result->Set(context, env()->status_string(),
699
568
                   Null(env()->isolate())).Check();
700
  }
701
702
1005
  if (term_signal_ > 0)
703
51
    js_result->Set(context, env()->signal_string(),
704
51
                   String::NewFromUtf8(env()->isolate(),
705
51
                                       signo_string(term_signal_))
706
204
                       .ToLocalChecked())
707
        .Check();
708
  else
709
954
    js_result->Set(context, env()->signal_string(),
710
3816
                   Null(env()->isolate())).Check();
711
712
1005
  if (exit_status_ >= 0)
713
863
    js_result->Set(context, env()->output_string(),
714
3452
                   BuildOutputArray()).Check();
715
  else
716
142
    js_result->Set(context, env()->output_string(),
717
568
                   Null(env()->isolate())).Check();
718
719
1005
  js_result->Set(context, env()->pid_string(),
720
4020
                 Number::New(env()->isolate(), uv_process_.pid)).Check();
721
722
1005
  return scope.Escape(js_result);
723
}
724
725
726
863
Local<Array> SyncProcessRunner::BuildOutputArray() {
727
863
  CHECK_GE(lifecycle_, kInitialized);
728
863
  CHECK(!stdio_pipes_.empty());
729
730
863
  EscapableHandleScope scope(env()->isolate());
731
863
  MaybeStackBuffer<Local<Value>, 8> js_output(stdio_pipes_.size());
732
733
3452
  for (uint32_t i = 0; i < stdio_pipes_.size(); i++) {
734
2589
    SyncProcessStdioPipe* h = stdio_pipes_[i].get();
735

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

1886
      } else if (!input->IsUndefined() && !input->IsNull()) {
918
        // Strings, numbers etc. are currently unsupported. It's not possible
919
        // to create a buffer for them here because there is no way to free
920
        // them afterwards.
921
        return UV_EINVAL;
922
      }
923
    }
924
925
2929
    return AddStdioPipe(child_fd, readable, writable, buf);
926
927

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

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