GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node.cc Lines: 409 466 87.8 %
Date: 2022-12-31 04:22:30 Branches: 256 373 68.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 "node.h"
23
24
// ========== local headers ==========
25
26
#include "debug_utils-inl.h"
27
#include "env-inl.h"
28
#include "histogram-inl.h"
29
#include "memory_tracker-inl.h"
30
#include "node_binding.h"
31
#include "node_builtins.h"
32
#include "node_errors.h"
33
#include "node_internals.h"
34
#include "node_main_instance.h"
35
#include "node_metadata.h"
36
#include "node_options-inl.h"
37
#include "node_perf.h"
38
#include "node_process-inl.h"
39
#include "node_realm-inl.h"
40
#include "node_report.h"
41
#include "node_revert.h"
42
#include "node_snapshot_builder.h"
43
#include "node_v8_platform-inl.h"
44
#include "node_version.h"
45
46
#if HAVE_OPENSSL
47
#include "node_crypto.h"
48
#endif
49
50
#if defined(NODE_HAVE_I18N_SUPPORT)
51
#include "node_i18n.h"
52
#endif
53
54
#if HAVE_INSPECTOR
55
#include "inspector_agent.h"
56
#include "inspector_io.h"
57
#endif
58
59
#if NODE_USE_V8_PLATFORM
60
#include "libplatform/libplatform.h"
61
#endif  // NODE_USE_V8_PLATFORM
62
#include "v8-profiler.h"
63
64
#if HAVE_INSPECTOR
65
#include "inspector/worker_inspector.h"  // ParentInspectorHandle
66
#endif
67
68
#ifdef NODE_ENABLE_VTUNE_PROFILING
69
#include "../deps/v8/src/third_party/vtune/v8-vtune.h"
70
#endif
71
72
#include "large_pages/node_large_page.h"
73
74
#if defined(__APPLE__) || defined(__linux__) || defined(_WIN32)
75
#define NODE_USE_V8_WASM_TRAP_HANDLER 1
76
#else
77
#define NODE_USE_V8_WASM_TRAP_HANDLER 0
78
#endif
79
80
#if NODE_USE_V8_WASM_TRAP_HANDLER
81
#if defined(_WIN32)
82
#include "v8-wasm-trap-handler-win.h"
83
#else
84
#include <atomic>
85
#include "v8-wasm-trap-handler-posix.h"
86
#endif
87
#endif  // NODE_USE_V8_WASM_TRAP_HANDLER
88
89
// ========== global C headers ==========
90
91
#include <fcntl.h>  // _O_RDWR
92
#include <sys/types.h>
93
94
#if defined(NODE_HAVE_I18N_SUPPORT)
95
#include <unicode/uvernum.h>
96
#include <unicode/utypes.h>
97
#endif
98
99
100
#if defined(LEAK_SANITIZER)
101
#include <sanitizer/lsan_interface.h>
102
#endif
103
104
#if defined(_MSC_VER)
105
#include <direct.h>
106
#include <io.h>
107
#define STDIN_FILENO 0
108
#else
109
#include <pthread.h>
110
#include <sys/resource.h>  // getrlimit, setrlimit
111
#include <termios.h>       // tcgetattr, tcsetattr
112
#include <unistd.h>        // STDIN_FILENO, STDERR_FILENO
113
#endif
114
115
// ========== global C++ headers ==========
116
117
#include <cerrno>
118
#include <climits>  // PATH_MAX
119
#include <csignal>
120
#include <cstdio>
121
#include <cstdlib>
122
#include <cstring>
123
124
#include <string>
125
#include <vector>
126
127
namespace node {
128
129
using builtins::BuiltinLoader;
130
131
using v8::EscapableHandleScope;
132
using v8::Isolate;
133
using v8::Local;
134
using v8::MaybeLocal;
135
using v8::Object;
136
using v8::V8;
137
using v8::Value;
138
139
namespace per_process {
140
141
// node_revert.h
142
// Bit flag used to track security reverts.
143
unsigned int reverted_cve = 0;
144
145
// util.h
146
// Tells whether the per-process V8::Initialize() is called and
147
// if it is safe to call v8::Isolate::TryGetCurrent().
148
bool v8_initialized = false;
149
150
// node_internals.h
151
// process-relative uptime base in nanoseconds, initialized in node::Start()
152
uint64_t node_start_time;
153
154
#if NODE_USE_V8_WASM_TRAP_HANDLER && defined(_WIN32)
155
PVOID old_vectored_exception_handler;
156
#endif
157
158
// node_v8_platform-inl.h
159
struct V8Platform v8_platform;
160
}  // namespace per_process
161
162
// The section in the OpenSSL configuration file to be loaded.
163
const char* conf_section_name = STRINGIFY(NODE_OPENSSL_CONF_NAME);
164
165
#ifdef __POSIX__
166
void SignalExit(int signo, siginfo_t* info, void* ucontext) {
167
  ResetStdio();
168
  raise(signo);
169
}
170
#endif  // __POSIX__
171
172
#if HAVE_INSPECTOR
173
6530
void Environment::InitializeInspector(
174
    std::unique_ptr<inspector::ParentInspectorHandle> parent_handle) {
175
13060
  std::string inspector_path;
176
6530
  bool is_main = !parent_handle;
177
6530
  if (parent_handle) {
178
765
    inspector_path = parent_handle->url();
179
765
    inspector_agent_->SetParentHandle(std::move(parent_handle));
180
  } else {
181
5765
    inspector_path = argv_.size() > 1 ? argv_[1].c_str() : "";
182
  }
183
184
6530
  CHECK(!inspector_agent_->IsListening());
185
  // Inspector agent can't fail to start, but if it was configured to listen
186
  // right away on the websocket port and fails to bind/etc, this will return
187
  // false.
188
13060
  inspector_agent_->Start(inspector_path,
189
6530
                          options_->debug_options(),
190
13060
                          inspector_host_port(),
191
                          is_main);
192

6648
  if (options_->debug_options().inspector_enabled &&
193
118
      !inspector_agent_->IsListening()) {
194
8
    return;
195
  }
196
197
6522
  profiler::StartProfilers(this);
198
199
6522
  if (inspector_agent_->options().break_node_first_line) {
200
1
    inspector_agent_->PauseOnNextJavascriptStatement("Break at bootstrap");
201
  }
202
203
6522
  return;
204
}
205
#endif  // HAVE_INSPECTOR
206
207
#define ATOMIC_WAIT_EVENTS(V)                                               \
208
  V(kStartWait,           "started")                                        \
209
  V(kWokenUp,             "was woken up by another thread")                 \
210
  V(kTimedOut,            "timed out")                                      \
211
  V(kTerminatedExecution, "was stopped by terminated execution")            \
212
  V(kAPIStopped,          "was stopped through the embedder API")           \
213
  V(kNotEqual,            "did not wait because the values mismatched")     \
214
215
8
static void AtomicsWaitCallback(Isolate::AtomicsWaitEvent event,
216
                                Local<v8::SharedArrayBuffer> array_buffer,
217
                                size_t offset_in_bytes, int64_t value,
218
                                double timeout_in_ms,
219
                                Isolate::AtomicsWaitWakeHandle* stop_handle,
220
                                void* data) {
221
8
  Environment* env = static_cast<Environment*>(data);
222
223
8
  const char* message = "(unknown event)";
224

8
  switch (event) {
225
#define V(key, msg)                         \
226
    case Isolate::AtomicsWaitEvent::key:    \
227
      message = msg;                        \
228
      break;
229
8
    ATOMIC_WAIT_EVENTS(V)
230
#undef V
231
  }
232
233
16
  fprintf(stderr,
234
          "(node:%d) [Thread %" PRIu64 "] Atomics.wait(%p + %zx, %" PRId64
235
          ", %.f) %s\n",
236
8
          static_cast<int>(uv_os_getpid()),
237
          env->thread_id(),
238
          array_buffer->Data(),
239
          offset_in_bytes,
240
          value,
241
          timeout_in_ms,
242
          message);
243
8
}
244
245
6495
void Environment::InitializeDiagnostics() {
246
6495
  isolate_->GetHeapProfiler()->AddBuildEmbedderGraphCallback(
247
      Environment::BuildEmbedderGraph, this);
248
6495
  if (heap_snapshot_near_heap_limit_ > 0) {
249
1
    AddHeapSnapshotNearHeapLimitCallback();
250
  }
251
6495
  if (options_->trace_uncaught)
252
3
    isolate_->SetCaptureStackTraceForUncaughtExceptions(true);
253
6495
  if (options_->trace_atomics_wait) {
254
2
    isolate_->SetAtomicsWaitCallback(AtomicsWaitCallback, this);
255
2
    AddCleanupHook([](void* data) {
256
2
      Environment* env = static_cast<Environment*>(data);
257
2
      env->isolate()->SetAtomicsWaitCallback(nullptr, nullptr);
258
2
    }, this);
259
  }
260
6495
}
261
262
static
263
6495
MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
264
6495
  EscapableHandleScope scope(env->isolate());
265
6495
  CHECK_NOT_NULL(main_script_id);
266
6495
  Realm* realm = env->principal_realm();
267
268
12691
  return scope.EscapeMaybe(realm->ExecuteBootstrapper(main_script_id));
269
}
270
271
6495
MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
272
  InternalCallbackScope callback_scope(
273
      env,
274
      Object::New(env->isolate()),
275
      { 1, 0 },
276
12689
      InternalCallbackScope::kSkipAsyncHooks);
277
278
6495
  if (cb != nullptr) {
279
25
    EscapableHandleScope scope(env->isolate());
280
281
50
    if (StartExecution(env, "internal/main/environment").IsEmpty()) return {};
282
283
    StartExecutionCallbackInfo info = {
284
25
        env->process_object(),
285
25
        env->builtin_module_require(),
286
    };
287
288
48
    return scope.EscapeMaybe(cb(info));
289
  }
290
291
  // TODO(joyeecheung): move these conditions into JS land and let the
292
  // deserialize main function take precedence. For workers, we need to
293
  // move the pre-execution part into a different file that can be
294
  // reused when dealing with user-defined main functions.
295
12940
  if (!env->snapshot_deserialize_main().IsEmpty()) {
296
    return env->RunSnapshotDeserializeMain();
297
  }
298
299
6470
  if (env->worker_context() != nullptr) {
300
756
    return StartExecution(env, "internal/main/worker_thread");
301
  }
302
303
11129
  std::string first_argv;
304
5714
  if (env->argv().size() > 1) {
305
5155
    first_argv = env->argv()[1];
306
  }
307
308
5714
  if (first_argv == "inspect") {
309
38
    return StartExecution(env, "internal/main/inspect");
310
  }
311
312
5676
  if (per_process::cli_options->build_snapshot) {
313
2
    return StartExecution(env, "internal/main/mksnapshot");
314
  }
315
316
5674
  if (per_process::cli_options->print_help) {
317
2
    return StartExecution(env, "internal/main/print_help");
318
  }
319
320
321
5672
  if (env->options()->prof_process) {
322
1
    return StartExecution(env, "internal/main/prof_process");
323
  }
324
325
  // -e/--eval without -i/--interactive
326


5671
  if (env->options()->has_eval_string && !env->options()->force_repl) {
327
520
    return StartExecution(env, "internal/main/eval_string");
328
  }
329
330
5151
  if (env->options()->syntax_check_only) {
331
39
    return StartExecution(env, "internal/main/check_syntax");
332
  }
333
334
5112
  if (env->options()->test_runner) {
335
31
    return StartExecution(env, "internal/main/test_runner");
336
  }
337
338
5081
  if (env->options()->watch_mode) {
339
11
    return StartExecution(env, "internal/main/watch_mode");
340
  }
341
342

5070
  if (!first_argv.empty() && first_argv != "-") {
343
5022
    return StartExecution(env, "internal/main/run_main_module");
344
  }
345
346


48
  if (env->options()->force_repl || uv_guess_handle(STDIN_FILENO) == UV_TTY) {
347
30
    return StartExecution(env, "internal/main/repl");
348
  }
349
350
18
  return StartExecution(env, "internal/main/eval_stdin");
351
}
352
353
#ifdef __POSIX__
354
typedef void (*sigaction_cb)(int signo, siginfo_t* info, void* ucontext);
355
#endif
356
#if NODE_USE_V8_WASM_TRAP_HANDLER
357
#if defined(_WIN32)
358
static LONG TrapWebAssemblyOrContinue(EXCEPTION_POINTERS* exception) {
359
  if (v8::TryHandleWebAssemblyTrapWindows(exception)) {
360
    return EXCEPTION_CONTINUE_EXECUTION;
361
  }
362
  return EXCEPTION_CONTINUE_SEARCH;
363
}
364
#else
365
static std::atomic<sigaction_cb> previous_sigsegv_action;
366
367
6
void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) {
368
6
  if (!v8::TryHandleWebAssemblyTrapPosix(signo, info, ucontext)) {
369
6
    sigaction_cb prev = previous_sigsegv_action.load();
370
6
    if (prev != nullptr) {
371
6
      prev(signo, info, ucontext);
372
    } else {
373
      // Reset to the default signal handler, i.e. cause a hard crash.
374
      struct sigaction sa;
375
      memset(&sa, 0, sizeof(sa));
376
      sa.sa_handler = SIG_DFL;
377
      CHECK_EQ(sigaction(signo, &sa, nullptr), 0);
378
379
      ResetStdio();
380
      raise(signo);
381
    }
382
  }
383
6
}
384
#endif  // defined(_WIN32)
385
#endif  // NODE_USE_V8_WASM_TRAP_HANDLER
386
387
#ifdef __POSIX__
388
18507
void RegisterSignalHandler(int signal,
389
                           sigaction_cb handler,
390
                           bool reset_handler) {
391
18507
  CHECK_NOT_NULL(handler);
392
#if NODE_USE_V8_WASM_TRAP_HANDLER
393
18507
  if (signal == SIGSEGV) {
394
4
    CHECK(previous_sigsegv_action.is_lock_free());
395
4
    CHECK(!reset_handler);
396
4
    previous_sigsegv_action.store(handler);
397
4
    return;
398
  }
399
#endif  // NODE_USE_V8_WASM_TRAP_HANDLER
400
  struct sigaction sa;
401
18503
  memset(&sa, 0, sizeof(sa));
402
18503
  sa.sa_sigaction = handler;
403
18503
  sa.sa_flags = reset_handler ? SA_RESETHAND : 0;
404
18503
  sigfillset(&sa.sa_mask);
405
18503
  CHECK_EQ(sigaction(signal, &sa, nullptr), 0);
406
}
407
#endif  // __POSIX__
408
409
#ifdef __POSIX__
410
static struct {
411
  int flags;
412
  bool isatty;
413
  struct stat stat;
414
  struct termios termios;
415
} stdio[1 + STDERR_FILENO];
416
#endif  // __POSIX__
417
418
10905
void ResetSignalHandlers() {
419
#ifdef __POSIX__
420
  // Restore signal dispositions, the parent process may have changed them.
421
  struct sigaction act;
422
10905
  memset(&act, 0, sizeof(act));
423
424
  // The hard-coded upper limit is because NSIG is not very reliable; on Linux,
425
  // it evaluates to 32, 34 or 64, depending on whether RT signals are enabled.
426
  // Counting up to SIGRTMIN doesn't work for the same reason.
427
348960
  for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
428

338055
    if (nr == SIGKILL || nr == SIGSTOP)
429
21810
      continue;
430

316245
    act.sa_handler = (nr == SIGPIPE || nr == SIGXFSZ) ? SIG_IGN : SIG_DFL;
431
316245
    CHECK_EQ(0, sigaction(nr, &act, nullptr));
432
  }
433
#endif  // __POSIX__
434
10905
}
435
436
static std::atomic<uint32_t> init_process_flags = 0;
437
438
5787
static void PlatformInit(ProcessInitializationFlags::Flags flags) {
439
  // init_process_flags is accessed in ResetStdio(),
440
  // which can be called from signal handlers.
441
5787
  CHECK(init_process_flags.is_lock_free());
442
5787
  init_process_flags.store(flags);
443
444
5787
  if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) {
445
5787
    atexit(ResetStdio);
446
  }
447
448
#ifdef __POSIX__
449
5787
  if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) {
450
    // Disable stdio buffering, it interacts poorly with printf()
451
    // calls elsewhere in the program (e.g., any logging from V8.)
452
5787
    setvbuf(stdout, nullptr, _IONBF, 0);
453
5787
    setvbuf(stderr, nullptr, _IONBF, 0);
454
455
    // Make sure file descriptors 0-2 are valid before we start logging
456
    // anything.
457
23148
    for (auto& s : stdio) {
458
17361
      const int fd = &s - stdio;
459
17361
      if (fstat(fd, &s.stat) == 0) continue;
460
461
      // Anything but EBADF means something is seriously wrong.  We don't
462
      // have to special-case EINTR, fstat() is not interruptible.
463
2
      if (errno != EBADF) ABORT();
464
465
      // If EBADF (file descriptor doesn't exist), open /dev/null and duplicate
466
      // its file descriptor to the invalid file descriptor.  Make sure *that*
467
      // file descriptor is valid.  POSIX doesn't guarantee the next file
468
      // descriptor open(2) gives us is the lowest available number anymore in
469
      // POSIX.1-2017, which is why dup2(2) is needed.
470
      int null_fd;
471
472
      do {
473
2
        null_fd = open("/dev/null", O_RDWR);
474

2
      } while (null_fd < 0 && errno == EINTR);
475
476
2
      if (null_fd != fd) {
477
        int err;
478
479
        do {
480
          err = dup2(null_fd, fd);
481
        } while (err < 0 && errno == EINTR);
482
        CHECK_EQ(err, 0);
483
      }
484
485
2
      if (fstat(fd, &s.stat) < 0) ABORT();
486
    }
487
  }
488
489
5787
  if (!(flags & ProcessInitializationFlags::kNoDefaultSignalHandling)) {
490
#if HAVE_INSPECTOR
491
    sigset_t sigmask;
492
5787
    sigemptyset(&sigmask);
493
5787
    sigaddset(&sigmask, SIGUSR1);
494
5787
    const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
495
5787
    CHECK_EQ(err, 0);
496
#endif  // HAVE_INSPECTOR
497
498
5787
    ResetSignalHandlers();
499
  }
500
501
5787
  if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) {
502
    // Record the state of the stdio file descriptors so we can restore it
503
    // on exit.  Needs to happen before installing signal handlers because
504
    // they make use of that information.
505
23148
    for (auto& s : stdio) {
506
17361
      const int fd = &s - stdio;
507
      int err;
508
509
      do {
510
17361
        s.flags = fcntl(fd, F_GETFL);
511

17361
      } while (s.flags == -1 && errno == EINTR);  // NOLINT
512
17361
      CHECK_NE(s.flags, -1);
513
514
17361
      if (uv_guess_handle(fd) != UV_TTY) continue;
515
120
      s.isatty = true;
516
517
      do {
518
120
        err = tcgetattr(fd, &s.termios);
519

120
      } while (err == -1 && errno == EINTR);  // NOLINT
520
120
      CHECK_EQ(err, 0);
521
    }
522
  }
523
524
5787
  if (!(flags & ProcessInitializationFlags::kNoDefaultSignalHandling)) {
525
5787
    RegisterSignalHandler(SIGINT, SignalExit, true);
526
5787
    RegisterSignalHandler(SIGTERM, SignalExit, true);
527
528
#if NODE_USE_V8_WASM_TRAP_HANDLER
529
#if defined(_WIN32)
530
    {
531
      constexpr ULONG first = TRUE;
532
      per_process::old_vectored_exception_handler =
533
          AddVectoredExceptionHandler(first, TrapWebAssemblyOrContinue);
534
    }
535
#else
536
    // Tell V8 to disable emitting WebAssembly
537
    // memory bounds checks. This means that we have
538
    // to catch the SIGSEGV in TrapWebAssemblyOrContinue
539
    // and pass the signal context to V8.
540
    {
541
      struct sigaction sa;
542
5787
      memset(&sa, 0, sizeof(sa));
543
5787
      sa.sa_sigaction = TrapWebAssemblyOrContinue;
544
5787
      sa.sa_flags = SA_SIGINFO;
545
5787
      CHECK_EQ(sigaction(SIGSEGV, &sa, nullptr), 0);
546
    }
547
#endif  // defined(_WIN32)
548
5787
    V8::EnableWebAssemblyTrapHandler(false);
549
#endif  // NODE_USE_V8_WASM_TRAP_HANDLER
550
  }
551
552
5787
  if (!(flags & ProcessInitializationFlags::kNoAdjustResourceLimits)) {
553
    // Raise the open file descriptor limit.
554
    struct rlimit lim;
555

5787
    if (getrlimit(RLIMIT_NOFILE, &lim) == 0 && lim.rlim_cur != lim.rlim_max) {
556
      // Do a binary search for the limit.
557
      rlim_t min = lim.rlim_cur;
558
      rlim_t max = 1 << 20;
559
      // But if there's a defined upper bound, don't search, just set it.
560
      if (lim.rlim_max != RLIM_INFINITY) {
561
        min = lim.rlim_max;
562
        max = lim.rlim_max;
563
      }
564
      do {
565
        lim.rlim_cur = min + (max - min) / 2;
566
        if (setrlimit(RLIMIT_NOFILE, &lim)) {
567
          max = lim.rlim_cur;
568
        } else {
569
          min = lim.rlim_cur;
570
        }
571
      } while (min + 1 < max);
572
    }
573
  }
574
#endif  // __POSIX__
575
#ifdef _WIN32
576
  if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) {
577
    for (int fd = 0; fd <= 2; ++fd) {
578
      auto handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
579
      if (handle == INVALID_HANDLE_VALUE ||
580
          GetFileType(handle) == FILE_TYPE_UNKNOWN) {
581
        // Ignore _close result. If it fails or not depends on used Windows
582
        // version. We will just check _open result.
583
        _close(fd);
584
        if (fd != _open("nul", _O_RDWR)) ABORT();
585
      }
586
    }
587
  }
588
#endif  // _WIN32
589
5787
}
590
591
// Safe to call more than once and from signal handlers.
592
10927
void ResetStdio() {
593
21854
  if (init_process_flags.load() &
594
10927
      ProcessInitializationFlags::kNoStdioInitialization) {
595
    return;
596
  }
597
598
10927
  uv_tty_reset_mode();
599
#ifdef __POSIX__
600
43708
  for (auto& s : stdio) {
601
32781
    const int fd = &s - stdio;
602
603
    struct stat tmp;
604
32781
    if (-1 == fstat(fd, &tmp)) {
605
      CHECK_EQ(errno, EBADF);  // Program closed file descriptor.
606
6
      continue;
607
    }
608
609
32781
    bool is_same_file =
610

32781
        (s.stat.st_dev == tmp.st_dev && s.stat.st_ino == tmp.st_ino);
611
32781
    if (!is_same_file) continue;  // Program reopened file descriptor.
612
613
    int flags;
614
    do
615
32775
      flags = fcntl(fd, F_GETFL);
616

32775
    while (flags == -1 && errno == EINTR);  // NOLINT
617
32775
    CHECK_NE(flags, -1);
618
619
    // Restore the O_NONBLOCK flag if it changed.
620
32775
    if (O_NONBLOCK & (flags ^ s.flags)) {
621
1630
      flags &= ~O_NONBLOCK;
622
1630
      flags |= s.flags & O_NONBLOCK;
623
624
      int err;
625
      do
626
1630
        err = fcntl(fd, F_SETFL, flags);
627

1630
      while (err == -1 && errno == EINTR);  // NOLINT
628
1630
      CHECK_NE(err, -1);
629
    }
630
631
32775
    if (s.isatty) {
632
      sigset_t sa;
633
      int err;
634
635
      // We might be a background job that doesn't own the TTY so block SIGTTOU
636
      // before making the tcsetattr() call, otherwise that signal suspends us.
637
228
      sigemptyset(&sa);
638
228
      sigaddset(&sa, SIGTTOU);
639
640
228
      CHECK_EQ(0, pthread_sigmask(SIG_BLOCK, &sa, nullptr));
641
      do
642
228
        err = tcsetattr(fd, TCSANOW, &s.termios);
643

228
      while (err == -1 && errno == EINTR);  // NOLINT
644
228
      CHECK_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sa, nullptr));
645
646
      // Normally we expect err == 0. But if macOS App Sandbox is enabled,
647
      // tcsetattr will fail with err == -1 and errno == EPERM.
648


228
      CHECK_IMPLIES(err != 0, err == -1 && errno == EPERM);
649
    }
650
  }
651
#endif  // __POSIX__
652
}
653
654
11436
static ExitCode ProcessGlobalArgsInternal(std::vector<std::string>* args,
655
                                          std::vector<std::string>* exec_args,
656
                                          std::vector<std::string>* errors,
657
                                          OptionEnvvarSettings settings) {
658
  // Parse a few arguments which are specific to Node.
659
22872
  std::vector<std::string> v8_args;
660
661
22872
  Mutex::ScopedLock lock(per_process::cli_options_mutex);
662
11436
  options_parser::Parse(
663
      args,
664
      exec_args,
665
      &v8_args,
666
      per_process::cli_options.get(),
667
      settings,
668
      errors);
669
670
11436
  if (!errors->empty()) return ExitCode::kInvalidCommandLineArgument;
671
672
22774
  std::string revert_error;
673
11387
  for (const std::string& cve : per_process::cli_options->security_reverts) {
674
1
    Revert(cve.c_str(), &revert_error);
675
1
    if (!revert_error.empty()) {
676
1
      errors->emplace_back(std::move(revert_error));
677
      // TODO(joyeecheung): merge into kInvalidCommandLineArgument.
678
1
      return ExitCode::kInvalidCommandLineArgument2;
679
    }
680
  }
681
682
22771
  if (per_process::cli_options->disable_proto != "delete" &&
683

22771
      per_process::cli_options->disable_proto != "throw" &&
684
11384
      per_process::cli_options->disable_proto != "") {
685
    errors->emplace_back("invalid mode passed to --disable-proto");
686
    // TODO(joyeecheung): merge into kInvalidCommandLineArgument.
687
    return ExitCode::kInvalidCommandLineArgument2;
688
  }
689
690
  // TODO(aduh95): remove this when the harmony-import-assertions flag
691
  // is removed in V8.
692
22772
  if (std::find(v8_args.begin(), v8_args.end(),
693
11386
                "--no-harmony-import-assertions") == v8_args.end()) {
694
11386
    v8_args.emplace_back("--harmony-import-assertions");
695
  }
696
697
22772
  auto env_opts = per_process::cli_options->per_isolate->per_env;
698
22772
  if (std::find(v8_args.begin(), v8_args.end(),
699

22754
                "--abort-on-uncaught-exception") != v8_args.end() ||
700
11386
      std::find(v8_args.begin(), v8_args.end(),
701
22754
                "--abort_on_uncaught_exception") != v8_args.end()) {
702
21
    env_opts->abort_on_uncaught_exception = true;
703
  }
704
705
#ifdef __POSIX__
706
  // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc.  Avoids the
707
  // performance penalty of frequent EINTR wakeups when the profiler is running.
708
  // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
709
11386
  if (std::find(v8_args.begin(), v8_args.end(), "--prof") != v8_args.end()) {
710
2
    uv_loop_configure(uv_default_loop(), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
711
  }
712
#endif
713
714
22772
  std::vector<char*> v8_args_as_char_ptr(v8_args.size());
715
11386
  if (v8_args.size() > 0) {
716
34339
    for (size_t i = 0; i < v8_args.size(); ++i)
717
22953
      v8_args_as_char_ptr[i] = &v8_args[i][0];
718
11386
    int argc = v8_args.size();
719
11386
    V8::SetFlagsFromCommandLine(&argc, &v8_args_as_char_ptr[0], true);
720
11386
    v8_args_as_char_ptr.resize(argc);
721
  }
722
723
  // Anything that's still in v8_argv is not a V8 or a node option.
724
11387
  for (size_t i = 1; i < v8_args_as_char_ptr.size(); i++)
725
1
    errors->push_back("bad option: " + std::string(v8_args_as_char_ptr[i]));
726
727
11386
  if (v8_args_as_char_ptr.size() > 1)
728
1
    return ExitCode::kInvalidCommandLineArgument;
729
730
11385
  return ExitCode::kNoFailure;
731
}
732
733
int ProcessGlobalArgs(std::vector<std::string>* args,
734
                      std::vector<std::string>* exec_args,
735
                      std::vector<std::string>* errors,
736
                      OptionEnvvarSettings settings) {
737
  return static_cast<int>(
738
      ProcessGlobalArgsInternal(args, exec_args, errors, settings));
739
}
740
741
static std::atomic_bool init_called{false};
742
743
// TODO(addaleax): Turn this into a wrapper around InitializeOncePerProcess()
744
// (with the corresponding additional flags set), then eventually remove this.
745
5788
static ExitCode InitializeNodeWithArgsInternal(
746
    std::vector<std::string>* argv,
747
    std::vector<std::string>* exec_argv,
748
    std::vector<std::string>* errors,
749
    ProcessInitializationFlags::Flags flags) {
750
  // Make sure InitializeNodeWithArgs() is called only once.
751
5788
  CHECK(!init_called.exchange(true));
752
753
  // Initialize node_start_time to get relative uptime.
754
5788
  per_process::node_start_time = uv_hrtime();
755
756
  // Register built-in bindings
757
5788
  binding::RegisterBuiltinBindings();
758
759
  // Make inherited handles noninheritable.
760
5788
  if (!(flags & ProcessInitializationFlags::kEnableStdioInheritance) &&
761
5788
      !(flags & ProcessInitializationFlags::kNoStdioInitialization)) {
762
5788
    uv_disable_stdio_inheritance();
763
  }
764
765
  // Cache the original command line to be
766
  // used in diagnostic reports.
767
5788
  per_process::cli_options->cmdline = *argv;
768
769
  // Node provides a "v8.setFlagsFromString" method to dynamically change flags.
770
  // Hence do not freeze flags when initializing V8. In a browser setting, this
771
  // is security relevant, for Node it's less important.
772
5788
  V8::SetFlagsFromString("--no-freeze-flags-after-init");
773
774
#if defined(NODE_V8_OPTIONS)
775
  // Should come before the call to V8::SetFlagsFromCommandLine()
776
  // so the user can disable a flag --foo at run-time by passing
777
  // --no_foo from the command line.
778
  V8::SetFlagsFromString(NODE_V8_OPTIONS, sizeof(NODE_V8_OPTIONS) - 1);
779
#endif
780
781
5788
  HandleEnvOptions(per_process::cli_options->per_isolate->per_env);
782
783
#if !defined(NODE_WITHOUT_NODE_OPTIONS)
784
5788
  if (!(flags & ProcessInitializationFlags::kDisableNodeOptionsEnv)) {
785
5788
    std::string node_options;
786
787
5788
    if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) {
788
      std::vector<std::string> env_argv =
789
5666
          ParseNodeOptionsEnvVar(node_options, errors);
790
791
5666
      if (!errors->empty()) return ExitCode::kInvalidCommandLineArgument;
792
793
      // [0] is expected to be the program name, fill it in from the real argv.
794
5666
      env_argv.insert(env_argv.begin(), argv->at(0));
795
796
5666
      const ExitCode exit_code = ProcessGlobalArgsInternal(
797
          &env_argv, nullptr, errors, kAllowedInEnvvar);
798
5666
      if (exit_code != ExitCode::kNoFailure) return exit_code;
799
    }
800
  }
801
#endif
802
803
5770
  if (!(flags & ProcessInitializationFlags::kDisableCLIOptions)) {
804
    const ExitCode exit_code =
805
5770
        ProcessGlobalArgsInternal(argv, exec_argv, errors, kDisallowedInEnvvar);
806
5770
    if (exit_code != ExitCode::kNoFailure) return exit_code;
807
  }
808
809
  // Set the process.title immediately after processing argv if --title is set.
810
5737
  if (!per_process::cli_options->title.empty())
811
2
    uv_set_process_title(per_process::cli_options->title.c_str());
812
813
#if defined(NODE_HAVE_I18N_SUPPORT)
814
5737
  if (!(flags & ProcessInitializationFlags::kNoICU)) {
815
    // If the parameter isn't given, use the env variable.
816
5737
    if (per_process::cli_options->icu_data_dir.empty())
817
11474
      credentials::SafeGetenv("NODE_ICU_DATA",
818
5737
                              &per_process::cli_options->icu_data_dir);
819
820
#ifdef NODE_ICU_DEFAULT_DATA_DIR
821
    // If neither the CLI option nor the environment variable was specified,
822
    // fall back to the configured default
823
    if (per_process::cli_options->icu_data_dir.empty()) {
824
      // Check whether the NODE_ICU_DEFAULT_DATA_DIR contains the right data
825
      // file and can be read.
826
      static const char full_path[] =
827
          NODE_ICU_DEFAULT_DATA_DIR "/" U_ICUDATA_NAME ".dat";
828
829
      FILE* f = fopen(full_path, "rb");
830
831
      if (f != nullptr) {
832
        fclose(f);
833
        per_process::cli_options->icu_data_dir = NODE_ICU_DEFAULT_DATA_DIR;
834
      }
835
    }
836
#endif  // NODE_ICU_DEFAULT_DATA_DIR
837
838
    // Initialize ICU.
839
    // If icu_data_dir is empty here, it will load the 'minimal' data.
840
5737
    if (!i18n::InitializeICUDirectory(per_process::cli_options->icu_data_dir)) {
841
      errors->push_back("could not initialize ICU "
842
                        "(check NODE_ICU_DATA or --icu-data-dir parameters)\n");
843
      return ExitCode::kInvalidCommandLineArgument;
844
    }
845
5737
    per_process::metadata.versions.InitializeIntlVersions();
846
  }
847
848
# ifndef __POSIX__
849
  std::string tz;
850
  if (credentials::SafeGetenv("TZ", &tz) && !tz.empty()) {
851
    i18n::SetDefaultTimeZone(tz.c_str());
852
  }
853
# endif
854
855
#endif  // defined(NODE_HAVE_I18N_SUPPORT)
856
857
  // We should set node_is_initialized here instead of in node::Start,
858
  // otherwise embedders using node::Init to initialize everything will not be
859
  // able to set it and native addons will not load for them.
860
5737
  node_is_initialized = true;
861
5737
  return ExitCode::kNoFailure;
862
}
863
864
1
int InitializeNodeWithArgs(std::vector<std::string>* argv,
865
                           std::vector<std::string>* exec_argv,
866
                           std::vector<std::string>* errors,
867
                           ProcessInitializationFlags::Flags flags) {
868
  return static_cast<int>(
869
1
      InitializeNodeWithArgsInternal(argv, exec_argv, errors, flags));
870
}
871
872
static std::unique_ptr<InitializationResultImpl>
873
5787
InitializeOncePerProcessInternal(const std::vector<std::string>& args,
874
                                 ProcessInitializationFlags::Flags flags =
875
                                     ProcessInitializationFlags::kNoFlags) {
876
5787
  auto result = std::make_unique<InitializationResultImpl>();
877
5787
  result->args_ = args;
878
879
5787
  if (!(flags & ProcessInitializationFlags::kNoParseGlobalDebugVariables)) {
880
    // Initialized the enabled list for Debug() calls with system
881
    // environment variables.
882
5787
    per_process::enabled_debug_list.Parse();
883
  }
884
885
5787
  PlatformInit(flags);
886
887
  // This needs to run *before* V8::Initialize().
888
  {
889
5787
    result->exit_code_ = InitializeNodeWithArgsInternal(
890
5787
        &result->args_, &result->exec_args_, &result->errors_, flags);
891
5787
    if (result->exit_code_enum() != ExitCode::kNoFailure) {
892
51
      result->early_return_ = true;
893
51
      return result;
894
    }
895
  }
896
897

17207
  if (!(flags & ProcessInitializationFlags::kNoUseLargePages) &&
898
11471
      (per_process::cli_options->use_largepages == "on" ||
899
5735
       per_process::cli_options->use_largepages == "silent")) {
900
1
    int lp_result = node::MapStaticCodeToLargePages();
901

1
    if (per_process::cli_options->use_largepages == "on" && lp_result != 0) {
902
      result->errors_.emplace_back(node::LargePagesError(lp_result));
903
    }
904
  }
905
906
5736
  if (!(flags & ProcessInitializationFlags::kNoPrintHelpOrVersionOutput)) {
907
5736
    if (per_process::cli_options->print_version) {
908
2
      printf("%s\n", NODE_VERSION);
909
2
      result->exit_code_ = ExitCode::kNoFailure;
910
2
      result->early_return_ = true;
911
2
      return result;
912
    }
913
914
5734
    if (per_process::cli_options->print_bash_completion) {
915
2
      std::string completion = options_parser::GetBashCompletion();
916
1
      printf("%s\n", completion.c_str());
917
1
      result->exit_code_ = ExitCode::kNoFailure;
918
1
      result->early_return_ = true;
919
1
      return result;
920
    }
921
922
5733
    if (per_process::cli_options->print_v8_help) {
923
      V8::SetFlagsFromString("--help", static_cast<size_t>(6));
924
      result->exit_code_ = ExitCode::kNoFailure;
925
      result->early_return_ = true;
926
      return result;
927
    }
928
  }
929
930
5733
  if (!(flags & ProcessInitializationFlags::kNoInitOpenSSL)) {
931
#if HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL)
932
2
    auto GetOpenSSLErrorString = []() -> std::string {
933
2
      std::string ret;
934
2
      ERR_print_errors_cb(
935
2
          [](const char* str, size_t len, void* opaque) {
936
2
            std::string* ret = static_cast<std::string*>(opaque);
937
2
            ret->append(str, len);
938
2
            ret->append("\n");
939
2
            return 0;
940
          },
941
          static_cast<void*>(&ret));
942
2
      return ret;
943
    };
944
945
    {
946
11466
      std::string extra_ca_certs;
947
5733
      if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs))
948
4
        crypto::UseExtraCaCerts(extra_ca_certs);
949
    }
950
    // In the case of FIPS builds we should make sure
951
    // the random source is properly initialized first.
952
#if OPENSSL_VERSION_MAJOR >= 3
953
    // Call OPENSSL_init_crypto to initialize OPENSSL_INIT_LOAD_CONFIG to
954
    // avoid the default behavior where errors raised during the parsing of the
955
    // OpenSSL configuration file are not propagated and cannot be detected.
956
    //
957
    // If FIPS is configured the OpenSSL configuration file will have an
958
    // .include pointing to the fipsmodule.cnf file generated by the openssl
959
    // fipsinstall command. If the path to this file is incorrect no error
960
    // will be reported.
961
    //
962
    // For Node.js this will mean that CSPRNG() will be called by V8 as
963
    // part of its initialization process, and CSPRNG() will in turn call
964
    // call RAND_status which will now always return 0, leading to an endless
965
    // loop and the node process will appear to hang/freeze.
966
967
    // Passing NULL as the config file will allow the default openssl.cnf file
968
    // to be loaded, but the default section in that file will not be used,
969
    // instead only the section that matches the value of conf_section_name
970
    // will be read from the default configuration file.
971
5733
    const char* conf_file = nullptr;
972
    // To allow for using the previous default where the 'openssl_conf' appname
973
    // was used, the command line option 'openssl-shared-config' can be used to
974
    // force the old behavior.
975
5733
    if (per_process::cli_options->openssl_shared_config) {
976
      conf_section_name = "openssl_conf";
977
    }
978
    // Use OPENSSL_CONF environment variable is set.
979
5733
    std::string env_openssl_conf;
980
5733
    credentials::SafeGetenv("OPENSSL_CONF", &env_openssl_conf);
981
5733
    if (!env_openssl_conf.empty()) {
982
1
      conf_file = env_openssl_conf.c_str();
983
    }
984
    // Use --openssl-conf command line option if specified.
985
5733
    if (!per_process::cli_options->openssl_config.empty()) {
986
3
      conf_file = per_process::cli_options->openssl_config.c_str();
987
    }
988
989
5733
    OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new();
990
5733
    OPENSSL_INIT_set_config_filename(settings, conf_file);
991
5733
    OPENSSL_INIT_set_config_appname(settings, conf_section_name);
992
5733
    OPENSSL_INIT_set_config_file_flags(settings,
993
                                       CONF_MFLAGS_IGNORE_MISSING_FILE);
994
995
5733
    OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings);
996
5733
    OPENSSL_INIT_free(settings);
997
998
5733
    if (ERR_peek_error() != 0) {
999
      // XXX: ERR_GET_REASON does not return something that is
1000
      // useful as an exit code at all.
1001
      result->exit_code_ =
1002
          static_cast<ExitCode>(ERR_GET_REASON(ERR_peek_error()));
1003
      result->early_return_ = true;
1004
      result->errors_.emplace_back("OpenSSL configuration error:\n" +
1005
                                   GetOpenSSLErrorString());
1006
      return result;
1007
    }
1008
#else  // OPENSSL_VERSION_MAJOR < 3
1009
    if (FIPS_mode()) {
1010
      OPENSSL_init();
1011
    }
1012
#endif
1013
5733
    if (!crypto::ProcessFipsOptions()) {
1014
      // XXX: ERR_GET_REASON does not return something that is
1015
      // useful as an exit code at all.
1016
2
      result->exit_code_ =
1017
2
          static_cast<ExitCode>(ERR_GET_REASON(ERR_peek_error()));
1018
2
      result->early_return_ = true;
1019
2
      result->errors_.emplace_back(
1020
4
          "OpenSSL error when trying to enable FIPS:\n" +
1021
6
          GetOpenSSLErrorString());
1022
2
      return result;
1023
    }
1024
1025
    // Ensure CSPRNG is properly seeded.
1026
5731
    CHECK(crypto::CSPRNG(nullptr, 0).is_ok());
1027
1028
5731
    V8::SetEntropySource([](unsigned char* buffer, size_t length) {
1029
      // V8 falls back to very weak entropy when this function fails
1030
      // and /dev/urandom isn't available. That wouldn't be so bad if
1031
      // the entropy was only used for Math.random() but it's also used for
1032
      // hash table and address space layout randomization. Better to abort.
1033
18715
      CHECK(crypto::CSPRNG(buffer, length).is_ok());
1034
18715
      return true;
1035
    });
1036
#endif  // HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL)
1037
  }
1038
1039
5731
  if (!(flags & ProcessInitializationFlags::kNoInitializeNodeV8Platform)) {
1040
5724
    per_process::v8_platform.Initialize(
1041
5724
        static_cast<int>(per_process::cli_options->v8_thread_pool_size));
1042
5724
    result->platform_ = per_process::v8_platform.Platform();
1043
  }
1044
1045
5731
  if (!(flags & ProcessInitializationFlags::kNoInitializeV8)) {
1046
    V8::Initialize();
1047
  }
1048
1049
5731
  performance::performance_v8_start = PERFORMANCE_NOW();
1050
5731
  per_process::v8_initialized = true;
1051
1052
5731
  return result;
1053
}
1054
1055
13
std::unique_ptr<InitializationResult> InitializeOncePerProcess(
1056
    const std::vector<std::string>& args,
1057
    ProcessInitializationFlags::Flags flags) {
1058
13
  return InitializeOncePerProcessInternal(args, flags);
1059
}
1060
1061
5118
void TearDownOncePerProcess() {
1062
5118
  const uint64_t flags = init_process_flags.load();
1063
5118
  ResetStdio();
1064
5118
  if (!(flags & ProcessInitializationFlags::kNoDefaultSignalHandling)) {
1065
5118
    ResetSignalHandlers();
1066
  }
1067
1068
5118
  per_process::v8_initialized = false;
1069
5118
  if (!(flags & ProcessInitializationFlags::kNoInitializeV8)) {
1070
5113
    V8::Dispose();
1071
  }
1072
1073
#if NODE_USE_V8_WASM_TRAP_HANDLER && defined(_WIN32)
1074
  if (!(flags & ProcessInitializationFlags::kNoDefaultSignalHandling)) {
1075
    RemoveVectoredExceptionHandler(per_process::old_vectored_exception_handler);
1076
  }
1077
#endif
1078
1079
5118
  if (!(flags & ProcessInitializationFlags::kNoInitializeNodeV8Platform)) {
1080
5113
    V8::DisposePlatform();
1081
    // uv_run cannot be called from the time before the beforeExit callback
1082
    // runs until the program exits unless the event loop has any referenced
1083
    // handles after beforeExit terminates. This prevents unrefed timers
1084
    // that happen to terminate during shutdown from being run unsafely.
1085
    // Since uv_run cannot be called, uv_async handles held by the platform
1086
    // will never be fully cleaned up.
1087
5113
    per_process::v8_platform.Dispose();
1088
  }
1089
5118
}
1090
1091
10348
InitializationResult::~InitializationResult() {}
1092
10348
InitializationResultImpl::~InitializationResultImpl() {}
1093
1094
4
ExitCode GenerateAndWriteSnapshotData(const SnapshotData** snapshot_data_ptr,
1095
                                      const InitializationResultImpl* result) {
1096
4
  ExitCode exit_code = result->exit_code_enum();
1097
  // nullptr indicates there's no snapshot data.
1098
  DCHECK_NULL(*snapshot_data_ptr);
1099
1100
  // node:embedded_snapshot_main indicates that we are using the
1101
  // embedded snapshot and we are not supposed to clean it up.
1102
4
  if (result->args()[1] == "node:embedded_snapshot_main") {
1103
2
    *snapshot_data_ptr = SnapshotBuilder::GetEmbeddedSnapshotData();
1104
2
    if (*snapshot_data_ptr == nullptr) {
1105
      // The Node.js binary is built without embedded snapshot
1106
      fprintf(stderr,
1107
              "node:embedded_snapshot_main was specified as snapshot "
1108
              "entry point but Node.js was built without embedded "
1109
              "snapshot.\n");
1110
      // TODO(joyeecheung): should be kInvalidCommandLineArgument instead.
1111
      exit_code = ExitCode::kGenericUserError;
1112
      return exit_code;
1113
    }
1114
  } else {
1115
    // Otherwise, load and run the specified main script.
1116
    std::unique_ptr<SnapshotData> generated_data =
1117
2
        std::make_unique<SnapshotData>();
1118
2
    exit_code = node::SnapshotBuilder::Generate(
1119
        generated_data.get(), result->args(), result->exec_args());
1120
2
    if (exit_code == ExitCode::kNoFailure) {
1121
1
      *snapshot_data_ptr = generated_data.release();
1122
    } else {
1123
1
      return exit_code;
1124
    }
1125
  }
1126
1127
  // Get the path to write the snapshot blob to.
1128
3
  std::string snapshot_blob_path;
1129
3
  if (!per_process::cli_options->snapshot_blob.empty()) {
1130
1
    snapshot_blob_path = per_process::cli_options->snapshot_blob;
1131
  } else {
1132
    // Defaults to snapshot.blob in the current working directory.
1133
2
    snapshot_blob_path = std::string("snapshot.blob");
1134
  }
1135
1136
3
  FILE* fp = fopen(snapshot_blob_path.c_str(), "wb");
1137
3
  if (fp != nullptr) {
1138
3
    (*snapshot_data_ptr)->ToBlob(fp);
1139
3
    fclose(fp);
1140
  } else {
1141
    fprintf(stderr,
1142
            "Cannot open %s for writing a snapshot.\n",
1143
            snapshot_blob_path.c_str());
1144
    // TODO(joyeecheung): should be kStartupSnapshotFailure.
1145
    exit_code = ExitCode::kGenericUserError;
1146
  }
1147
3
  return exit_code;
1148
}
1149
1150
5713
ExitCode LoadSnapshotDataAndRun(const SnapshotData** snapshot_data_ptr,
1151
                                const InitializationResultImpl* result) {
1152
5713
  ExitCode exit_code = result->exit_code_enum();
1153
  // nullptr indicates there's no snapshot data.
1154
  DCHECK_NULL(*snapshot_data_ptr);
1155
  // --snapshot-blob indicates that we are reading a customized snapshot.
1156
5713
  if (!per_process::cli_options->snapshot_blob.empty()) {
1157
3
    std::string filename = per_process::cli_options->snapshot_blob;
1158
3
    FILE* fp = fopen(filename.c_str(), "rb");
1159
3
    if (fp == nullptr) {
1160
1
      fprintf(stderr, "Cannot open %s", filename.c_str());
1161
      // TODO(joyeecheung): should be kStartupSnapshotFailure.
1162
1
      exit_code = ExitCode::kGenericUserError;
1163
1
      return exit_code;
1164
    }
1165
2
    std::unique_ptr<SnapshotData> read_data = std::make_unique<SnapshotData>();
1166
2
    if (!SnapshotData::FromBlob(read_data.get(), fp)) {
1167
      // If we fail to read the customized snapshot, simply exit with 1.
1168
      // TODO(joyeecheung): should be kStartupSnapshotFailure.
1169
      exit_code = ExitCode::kGenericUserError;
1170
      return exit_code;
1171
    }
1172
2
    *snapshot_data_ptr = read_data.release();
1173
2
    fclose(fp);
1174
5710
  } else if (per_process::cli_options->node_snapshot) {
1175
    // If --snapshot-blob is not specified, we are reading the embedded
1176
    // snapshot, but we will skip it if --no-node-snapshot is specified.
1177
    const node::SnapshotData* read_data =
1178
5707
        SnapshotBuilder::GetEmbeddedSnapshotData();
1179

5707
    if (read_data != nullptr && read_data->Check()) {
1180
      // If we fail to read the embedded snapshot, treat it as if Node.js
1181
      // was built without one.
1182
5707
      *snapshot_data_ptr = read_data;
1183
    }
1184
  }
1185
1186
5712
  if ((*snapshot_data_ptr) != nullptr) {
1187
5709
    BuiltinLoader::RefreshCodeCache((*snapshot_data_ptr)->code_cache);
1188
  }
1189
  NodeMainInstance main_instance(*snapshot_data_ptr,
1190
                                 uv_default_loop(),
1191
5712
                                 per_process::v8_platform.Platform(),
1192
                                 result->args(),
1193
11424
                                 result->exec_args());
1194
5712
  exit_code = main_instance.Run();
1195
5101
  return exit_code;
1196
}
1197
1198
5774
static ExitCode StartInternal(int argc, char** argv) {
1199
5774
  CHECK_GT(argc, 0);
1200
1201
  // Hack around with the argv pointer. Used for process.title = "blah".
1202
5774
  argv = uv_setup_args(argc, argv);
1203
1204
  std::unique_ptr<InitializationResultImpl> result =
1205
      InitializeOncePerProcessInternal(
1206
16711
          std::vector<std::string>(argv, argv + argc));
1207
5828
  for (const std::string& error : result->errors()) {
1208
54
    FPrintF(stderr, "%s: %s\n", result->args().at(0), error);
1209
  }
1210
5774
  if (result->early_return()) {
1211
56
    return result->exit_code_enum();
1212
  }
1213
1214
  DCHECK_EQ(result->exit_code_enum(), ExitCode::kNoFailure);
1215
5718
  const SnapshotData* snapshot_data = nullptr;
1216
1217
5107
  auto cleanup_process = OnScopeLeave([&]() {
1218
5107
    TearDownOncePerProcess();
1219
1220
5107
    if (snapshot_data != nullptr &&
1221
5101
        snapshot_data->data_ownership == SnapshotData::DataOwnership::kOwned) {
1222
3
      delete snapshot_data;
1223
    }
1224
10825
  });
1225
1226
5718
  uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME);
1227
1228
  // --build-snapshot indicates that we are in snapshot building mode.
1229
5718
  if (per_process::cli_options->build_snapshot) {
1230
5
    if (result->args().size() < 2) {
1231
1
      fprintf(stderr,
1232
              "--build-snapshot must be used with an entry point script.\n"
1233
              "Usage: node --build-snapshot /path/to/entry.js\n");
1234
1
      return ExitCode::kInvalidCommandLineArgument;
1235
    }
1236
4
    return GenerateAndWriteSnapshotData(&snapshot_data, result.get());
1237
  }
1238
1239
  // Without --build-snapshot, we are in snapshot loading mode.
1240
5713
  return LoadSnapshotDataAndRun(&snapshot_data, result.get());
1241
}
1242
1243
5774
int Start(int argc, char** argv) {
1244
5774
  return static_cast<int>(StartInternal(argc, argv));
1245
}
1246
1247
359
int Stop(Environment* env) {
1248
359
  env->ExitEnv();
1249
359
  return 0;
1250
}
1251
1252
}  // namespace node
1253
1254
#if !HAVE_INSPECTOR
1255
void Initialize() {}
1256
1257
NODE_BINDING_CONTEXT_AWARE_INTERNAL(inspector, Initialize)
1258
#endif  // !HAVE_INSPECTOR