GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node.cc Lines: 263 349 75.4 %
Date: 2019-02-01 22:03:38 Branches: 98 220 44.5 %

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_binding.h"
23
#include "node_buffer.h"
24
#include "node_constants.h"
25
#include "node_context_data.h"
26
#include "node_errors.h"
27
#include "node_internals.h"
28
#include "node_metadata.h"
29
#include "node_native_module.h"
30
#include "node_options-inl.h"
31
#include "node_perf.h"
32
#include "node_platform.h"
33
#include "node_process.h"
34
#include "node_revert.h"
35
#include "node_v8_platform-inl.h"
36
#include "node_version.h"
37
38
#if HAVE_OPENSSL
39
#include "node_crypto.h"
40
#endif
41
42
#if defined(NODE_HAVE_I18N_SUPPORT)
43
#include "node_i18n.h"
44
#endif
45
46
#if HAVE_INSPECTOR
47
#include "inspector_io.h"
48
#endif
49
50
#if defined HAVE_DTRACE || defined HAVE_ETW
51
#include "node_dtrace.h"
52
#endif
53
54
#include "async_wrap-inl.h"
55
#include "env-inl.h"
56
#include "handle_wrap.h"
57
#include "req_wrap-inl.h"
58
#include "string_bytes.h"
59
#include "util.h"
60
#include "uv.h"
61
#if NODE_USE_V8_PLATFORM
62
#include "libplatform/libplatform.h"
63
#endif  // NODE_USE_V8_PLATFORM
64
#include "v8-profiler.h"
65
66
#ifdef NODE_ENABLE_VTUNE_PROFILING
67
#include "../deps/v8/src/third_party/vtune/v8-vtune.h"
68
#endif
69
70
#ifdef NODE_ENABLE_LARGE_CODE_PAGES
71
#include "large_pages/node_large_page.h"
72
#endif
73
74
#include <errno.h>
75
#include <fcntl.h>  // _O_RDWR
76
#include <limits.h>  // PATH_MAX
77
#include <signal.h>
78
#include <stdio.h>
79
#include <stdlib.h>
80
#include <string.h>
81
#include <sys/types.h>
82
83
#include <string>
84
#include <vector>
85
86
#if defined(NODE_HAVE_I18N_SUPPORT)
87
#include <unicode/uvernum.h>
88
#endif
89
90
#ifdef NODE_REPORT
91
#include "node_report.h"
92
#endif
93
94
#if defined(LEAK_SANITIZER)
95
#include <sanitizer/lsan_interface.h>
96
#endif
97
98
#if defined(_MSC_VER)
99
#include <direct.h>
100
#include <io.h>
101
#define STDIN_FILENO 0
102
#else
103
#include <pthread.h>
104
#include <sys/resource.h>  // getrlimit, setrlimit
105
#include <unistd.h>        // STDIN_FILENO, STDERR_FILENO
106
#endif
107
108
namespace node {
109
110
using options_parser::kAllowedInEnvironment;
111
using options_parser::kDisallowedInEnvironment;
112
using v8::Array;
113
using v8::Boolean;
114
using v8::Context;
115
using v8::DEFAULT;
116
using v8::EscapableHandleScope;
117
using v8::Exception;
118
using v8::Function;
119
using v8::FunctionCallbackInfo;
120
using v8::HandleScope;
121
using v8::Int32;
122
using v8::Isolate;
123
using v8::Just;
124
using v8::Local;
125
using v8::Locker;
126
using v8::Maybe;
127
using v8::MaybeLocal;
128
using v8::Object;
129
using v8::Script;
130
using v8::SealHandleScope;
131
using v8::String;
132
using v8::Undefined;
133
using v8::V8;
134
using v8::Value;
135
136
namespace per_process {
137
// TODO(joyeecheung): these are no longer necessary. Remove them.
138
// See: https://github.com/nodejs/node/pull/25302#discussion_r244924196
139
// Isolate on the main thread
140
164
static Mutex main_isolate_mutex;
141
static Isolate* main_isolate;
142
143
// node_revert.h
144
// Bit flag used to track security reverts.
145
unsigned int reverted_cve = 0;
146
147
// util.h
148
// Tells whether the per-process V8::Initialize() is called and
149
// if it is safe to call v8::Isolate::GetCurrent().
150
bool v8_initialized = false;
151
152
// node_internals.h
153
// process-relative uptime base, initialized at start-up
154
double prog_start_time;
155
// Tells whether --prof is passed.
156
bool v8_is_profiling = false;
157
158
// node_v8_platform-inl.h
159
164
struct V8Platform v8_platform;
160
}  // namespace per_process
161
162
#ifdef __POSIX__
163
static const unsigned kMaxSignal = 32;
164
#endif
165
166
163
static void WaitForInspectorDisconnect(Environment* env) {
167
#if HAVE_INSPECTOR
168
163
  if (env->inspector_agent()->IsActive()) {
169
    // Restore signal dispositions, the app is done and is no longer
170
    // capable of handling signals.
171
#if defined(__POSIX__) && !defined(NODE_SHARED_MODE)
172
    struct sigaction act;
173
    memset(&act, 0, sizeof(act));
174
    for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
175
      if (nr == SIGKILL || nr == SIGSTOP || nr == SIGPROF)
176
        continue;
177
      act.sa_handler = (nr == SIGPIPE) ? SIG_IGN : SIG_DFL;
178
      CHECK_EQ(0, sigaction(nr, &act, nullptr));
179
    }
180
#endif
181
    env->inspector_agent()->WaitForDisconnect();
182
  }
183
#endif
184
163
}
185
186
9
void Exit(const FunctionCallbackInfo<Value>& args) {
187
9
  Environment* env = Environment::GetCurrent(args);
188
9
  WaitForInspectorDisconnect(env);
189
36
  int code = args[0]->Int32Value(env->context()).FromMaybe(0);
190
9
  env->Exit(code);
191
}
192
193
void SignalExit(int signo) {
194
  uv_tty_reset_mode();
195
#ifdef __FreeBSD__
196
  // FreeBSD has a nasty bug, see RegisterSignalHandler for details
197
  struct sigaction sa;
198
  memset(&sa, 0, sizeof(sa));
199
  sa.sa_handler = SIG_DFL;
200
  CHECK_EQ(sigaction(signo, &sa, nullptr), 0);
201
#endif
202
  raise(signo);
203
}
204
205
656
static MaybeLocal<Value> ExecuteBootstrapper(
206
    Environment* env,
207
    const char* id,
208
    std::vector<Local<String>>* parameters,
209
    std::vector<Local<Value>>* arguments) {
210
656
  EscapableHandleScope scope(env->isolate());
211
  MaybeLocal<Function> maybe_fn =
212
      per_process::native_module_loader.LookupAndCompile(
213
656
          env->context(), id, parameters, env);
214
215
656
  if (maybe_fn.IsEmpty()) {
216
    return MaybeLocal<Value>();
217
  }
218
219
656
  Local<Function> fn = maybe_fn.ToLocalChecked();
220
  MaybeLocal<Value> result = fn->Call(env->context(),
221
                                      Undefined(env->isolate()),
222
656
                                      arguments->size(),
223
2624
                                      arguments->data());
224
225
  // If there was an error during bootstrap then it was either handled by the
226
  // FatalException handler or it's unrecoverable (e.g. max call stack
227
  // exceeded). Either way, clear the stack so that the AsyncCallbackScope
228
  // destructor doesn't fail on the id check.
229
  // There are only two ways to have a stack size > 1: 1) the user manually
230
  // called MakeCallback or 2) user awaited during bootstrap, which triggered
231
  // _tickCallback().
232
656
  if (result.IsEmpty()) {
233
1
    env->async_hooks()->clear_async_id_stack();
234
  }
235
236
656
  return scope.EscapeMaybe(result);
237
}
238
239
164
MaybeLocal<Value> RunBootstrapping(Environment* env) {
240
164
  CHECK(!env->has_run_bootstrapping_code());
241
242
164
  EscapableHandleScope scope(env->isolate());
243
164
  Isolate* isolate = env->isolate();
244
164
  Local<Context> context = env->context();
245
246
  // Add a reference to the global object
247
164
  Local<Object> global = context->Global();
248
249
#if defined HAVE_DTRACE || defined HAVE_ETW
250
  InitDTrace(env, global);
251
#endif
252
253
164
  Local<Object> process = env->process_object();
254
255
  // Setting global properties for the bootstrappers to use:
256
  // - global
257
  // Expose the global object as a property on itself
258
  // (Allows you to set stuff on `global` from anywhere in JavaScript.)
259
492
  global->Set(context, FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global)
260
328
      .FromJust();
261
262
  // Store primordials
263
164
  env->set_primordials(Object::New(isolate));
264
  std::vector<Local<String>> primordials_params = {
265
    FIXED_ONE_BYTE_STRING(isolate, "breakAtBootstrap"),
266
    env->primordials_string()
267
328
  };
268
  std::vector<Local<Value>> primordials_args = {
269
    Boolean::New(isolate,
270
328
                  env->options()->debug_options().break_node_first_line),
271
    env->primordials()
272
656
  };
273
  MaybeLocal<Value> primordials_ret =
274
      ExecuteBootstrapper(env,
275
                          "internal/bootstrap/primordials",
276
                          &primordials_params,
277
164
                          &primordials_args);
278
164
  if (primordials_ret.IsEmpty()) {
279
    return MaybeLocal<Value>();
280
  }
281
282
  // Create binding loaders
283
  std::vector<Local<String>> loaders_params = {
284
      env->process_string(),
285
      FIXED_ONE_BYTE_STRING(isolate, "getBinding"),
286
      FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"),
287
      FIXED_ONE_BYTE_STRING(isolate, "getInternalBinding"),
288
      // --experimental-modules
289
      FIXED_ONE_BYTE_STRING(isolate, "experimentalModules"),
290
      // --expose-internals
291
      FIXED_ONE_BYTE_STRING(isolate, "exposeInternals"),
292
328
      env->primordials_string()};
293
  std::vector<Local<Value>> loaders_args = {
294
      process,
295
164
      env->NewFunctionTemplate(binding::GetBinding)
296
492
          ->GetFunction(context)
297
          .ToLocalChecked(),
298
164
      env->NewFunctionTemplate(binding::GetLinkedBinding)
299
492
          ->GetFunction(context)
300
          .ToLocalChecked(),
301
164
      env->NewFunctionTemplate(binding::GetInternalBinding)
302
492
          ->GetFunction(context)
303
          .ToLocalChecked(),
304
328
      Boolean::New(isolate, env->options()->experimental_modules),
305
328
      Boolean::New(isolate, env->options()->expose_internals),
306
1804
      env->primordials()};
307
308
  // Bootstrap internal loaders
309
  MaybeLocal<Value> loader_exports = ExecuteBootstrapper(
310
164
      env, "internal/bootstrap/loaders", &loaders_params, &loaders_args);
311
164
  if (loader_exports.IsEmpty()) {
312
    return MaybeLocal<Value>();
313
  }
314
315
  Local<Object> loader_exports_obj =
316
328
      loader_exports.ToLocalChecked().As<Object>();
317
  Local<Value> internal_binding_loader =
318
492
      loader_exports_obj->Get(context, env->internal_binding_string())
319
328
          .ToLocalChecked();
320
164
  env->set_internal_binding_loader(internal_binding_loader.As<Function>());
321
322
  Local<Value> require =
323
492
      loader_exports_obj->Get(context, env->require_string()).ToLocalChecked();
324
164
  env->set_native_module_require(require.As<Function>());
325
326
  // process, loaderExports, isMainThread
327
  std::vector<Local<String>> node_params = {
328
      env->process_string(),
329
      FIXED_ONE_BYTE_STRING(isolate, "loaderExports"),
330
      FIXED_ONE_BYTE_STRING(isolate, "isMainThread"),
331
328
      env->primordials_string()};
332
  std::vector<Local<Value>> node_args = {
333
      process,
334
      loader_exports_obj,
335
164
      Boolean::New(isolate, env->is_main_thread()),
336
656
      env->primordials()};
337
338
  MaybeLocal<Value> result = ExecuteBootstrapper(
339
164
      env, "internal/bootstrap/node", &node_params, &node_args);
340
341
164
  env->set_has_run_bootstrapping_code(true);
342
343
  return scope.EscapeMaybe(result);
344
}
345
346
164
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
347
164
  Environment* env = Environment::GetCurrent(args);
348
  env->performance_state()->Mark(
349
164
      performance::NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
350
164
}
351
352
164
MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
353
164
  EscapableHandleScope scope(env->isolate());
354
164
  CHECK_NE(main_script_id, nullptr);
355
356
  std::vector<Local<String>> parameters = {
357
      env->process_string(),
358
      env->require_string(),
359
      env->internal_binding_string(),
360
328
      FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
361
362
  std::vector<Local<Value>> arguments = {
363
      env->process_object(),
364
      env->native_module_require(),
365
      env->internal_binding_loader(),
366
164
      env->NewFunctionTemplate(MarkBootstrapComplete)
367
656
          ->GetFunction(env->context())
368
984
          .ToLocalChecked()};
369
370
  MaybeLocal<Value> result =
371
164
      ExecuteBootstrapper(env, main_script_id, &parameters, &arguments);
372
164
  return scope.EscapeMaybe(result);
373
}
374
375
164
MaybeLocal<Value> StartMainThreadExecution(Environment* env) {
376
  // To allow people to extend Node in different ways, this hook allows
377
  // one to drop a file lib/_third_party_main.js into the build
378
  // directory which will be executed instead of Node's normal loading.
379
164
  if (per_process::native_module_loader.Exists("_third_party_main")) {
380
    return StartExecution(env, "internal/main/run_third_party_main");
381
  }
382
383

328
  if (env->execution_mode() == Environment::ExecutionMode::kInspect ||
384
164
      env->execution_mode() == Environment::ExecutionMode::kDebug) {
385
    return StartExecution(env, "internal/main/inspect");
386
  }
387
388
164
  if (per_process::cli_options->print_help) {
389
    env->set_execution_mode(Environment::ExecutionMode::kPrintHelp);
390
    return StartExecution(env, "internal/main/print_help");
391
  }
392
393
164
  if (per_process::cli_options->print_bash_completion) {
394
    env->set_execution_mode(Environment::ExecutionMode::kPrintBashCompletion);
395
    return StartExecution(env, "internal/main/print_bash_completion");
396
  }
397
398
164
  if (env->options()->prof_process) {
399
    env->set_execution_mode(Environment::ExecutionMode::kPrintBashCompletion);
400
    return StartExecution(env, "internal/main/prof_process");
401
  }
402
403
  // -e/--eval without -i/--interactive
404


164
  if (env->options()->has_eval_string && !env->options()->force_repl) {
405
10
    env->set_execution_mode(Environment::ExecutionMode::kEvalString);
406
10
    return StartExecution(env, "internal/main/eval_string");
407
  }
408
409
154
  if (env->options()->syntax_check_only) {
410
    env->set_execution_mode(Environment::ExecutionMode::kCheckSyntax);
411
    return StartExecution(env, "internal/main/check_syntax");
412
  }
413
414
154
  if (env->execution_mode() == Environment::ExecutionMode::kRunMainModule) {
415
154
    return StartExecution(env, "internal/main/run_main_module");
416
  }
417
418
  if (env->options()->force_repl || uv_guess_handle(STDIN_FILENO) == UV_TTY) {
419
    env->set_execution_mode(Environment::ExecutionMode::kRepl);
420
    return StartExecution(env, "internal/main/repl");
421
  }
422
423
  env->set_execution_mode(Environment::ExecutionMode::kEvalStdin);
424
  return StartExecution(env, "internal/main/eval_stdin");
425
}
426
427
164
void LoadEnvironment(Environment* env) {
428
164
  CHECK(env->is_main_thread());
429
  // TODO(joyeecheung): Not all of the execution modes in
430
  // StartMainThreadExecution() make sense for embedders. Pick the
431
  // useful ones out, and allow embedders to customize the entry
432
  // point more directly without using _third_party_main.js
433
328
  if (!RunBootstrapping(env).IsEmpty()) {
434
164
    USE(StartMainThreadExecution(env));
435
  }
436
164
}
437
438
439
#ifdef __POSIX__
440
492
void RegisterSignalHandler(int signal,
441
                           void (*handler)(int signal),
442
                           bool reset_handler) {
443
  struct sigaction sa;
444
492
  memset(&sa, 0, sizeof(sa));
445
492
  sa.sa_handler = handler;
446
#ifndef __FreeBSD__
447
  // FreeBSD has a nasty bug with SA_RESETHAND reseting the SA_SIGINFO, that is
448
  // in turn set for a libthr wrapper. This leads to a crash.
449
  // Work around the issue by manually setting SIG_DFL in the signal handler
450
492
  sa.sa_flags = reset_handler ? SA_RESETHAND : 0;
451
#endif
452
492
  sigfillset(&sa.sa_mask);
453
492
  CHECK_EQ(sigaction(signal, &sa, nullptr), 0);
454
492
}
455
456
#endif  // __POSIX__
457
458
164
inline void PlatformInit() {
459
#ifdef __POSIX__
460
#if HAVE_INSPECTOR
461
  sigset_t sigmask;
462
164
  sigemptyset(&sigmask);
463
164
  sigaddset(&sigmask, SIGUSR1);
464
164
  const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
465
#endif  // HAVE_INSPECTOR
466
467
  // Make sure file descriptors 0-2 are valid before we start logging anything.
468
656
  for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
469
    struct stat ignored;
470
492
    if (fstat(fd, &ignored) == 0)
471
492
      continue;
472
    // Anything but EBADF means something is seriously wrong.  We don't
473
    // have to special-case EINTR, fstat() is not interruptible.
474
    if (errno != EBADF)
475
      ABORT();
476
    if (fd != open("/dev/null", O_RDWR))
477
      ABORT();
478
  }
479
480
#if HAVE_INSPECTOR
481
164
  CHECK_EQ(err, 0);
482
#endif  // HAVE_INSPECTOR
483
484
#ifndef NODE_SHARED_MODE
485
  // Restore signal dispositions, the parent process may have changed them.
486
  struct sigaction act;
487
164
  memset(&act, 0, sizeof(act));
488
489
  // The hard-coded upper limit is because NSIG is not very reliable; on Linux,
490
  // it evaluates to 32, 34 or 64, depending on whether RT signals are enabled.
491
  // Counting up to SIGRTMIN doesn't work for the same reason.
492
5248
  for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
493

5084
    if (nr == SIGKILL || nr == SIGSTOP)
494
328
      continue;
495
4756
    act.sa_handler = (nr == SIGPIPE) ? SIG_IGN : SIG_DFL;
496
4756
    CHECK_EQ(0, sigaction(nr, &act, nullptr));
497
  }
498
#endif  // !NODE_SHARED_MODE
499
500
164
  RegisterSignalHandler(SIGINT, SignalExit, true);
501
164
  RegisterSignalHandler(SIGTERM, SignalExit, true);
502
503
  // Raise the open file descriptor limit.
504
  struct rlimit lim;
505

164
  if (getrlimit(RLIMIT_NOFILE, &lim) == 0 && lim.rlim_cur != lim.rlim_max) {
506
    // Do a binary search for the limit.
507
    rlim_t min = lim.rlim_cur;
508
    rlim_t max = 1 << 20;
509
    // But if there's a defined upper bound, don't search, just set it.
510
    if (lim.rlim_max != RLIM_INFINITY) {
511
      min = lim.rlim_max;
512
      max = lim.rlim_max;
513
    }
514
    do {
515
      lim.rlim_cur = min + (max - min) / 2;
516
      if (setrlimit(RLIMIT_NOFILE, &lim)) {
517
        max = lim.rlim_cur;
518
      } else {
519
        min = lim.rlim_cur;
520
      }
521
    } while (min + 1 < max);
522
  }
523
#endif  // __POSIX__
524
#ifdef _WIN32
525
  for (int fd = 0; fd <= 2; ++fd) {
526
    auto handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
527
    if (handle == INVALID_HANDLE_VALUE ||
528
        GetFileType(handle) == FILE_TYPE_UNKNOWN) {
529
      // Ignore _close result. If it fails or not depends on used Windows
530
      // version. We will just check _open result.
531
      _close(fd);
532
      if (fd != _open("nul", _O_RDWR))
533
        ABORT();
534
    }
535
  }
536
#endif  // _WIN32
537
164
}
538
539
230
int ProcessGlobalArgs(std::vector<std::string>* args,
540
                      std::vector<std::string>* exec_args,
541
                      std::vector<std::string>* errors,
542
                      bool is_env) {
543
  // Parse a few arguments which are specific to Node.
544
230
  std::vector<std::string> v8_args;
545
546
460
  Mutex::ScopedLock lock(per_process::cli_options_mutex);
547
  options_parser::PerProcessOptionsParser::instance.Parse(
548
      args,
549
      exec_args,
550
      &v8_args,
551
      per_process::cli_options.get(),
552
      is_env ? kAllowedInEnvironment : kDisallowedInEnvironment,
553
230
      errors);
554
555
230
  if (!errors->empty()) return 9;
556
557
460
  std::string revert_error;
558
230
  for (const std::string& cve : per_process::cli_options->security_reverts) {
559
    Revert(cve.c_str(), &revert_error);
560
    if (!revert_error.empty()) {
561
      errors->emplace_back(std::move(revert_error));
562
      return 12;
563
    }
564
  }
565
566
460
  auto env_opts = per_process::cli_options->per_isolate->per_env;
567
460
  if (std::find(v8_args.begin(), v8_args.end(),
568


1380
                "--abort-on-uncaught-exception") != v8_args.end() ||
569
      std::find(v8_args.begin(), v8_args.end(),
570

920
                "--abort_on_uncaught_exception") != v8_args.end()) {
571
    env_opts->abort_on_uncaught_exception = true;
572
  }
573
574
  // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler
575
  // manually?  That would give us a little more control over its runtime
576
  // behavior but it could also interfere with the user's intentions in ways
577
  // we fail to anticipate.  Dillema.
578
230
  if (std::find(v8_args.begin(), v8_args.end(), "--prof") != v8_args.end()) {
579
    per_process::v8_is_profiling = true;
580
  }
581
582
#ifdef __POSIX__
583
  // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc.  Avoids the
584
  // performance penalty of frequent EINTR wakeups when the profiler is running.
585
  // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
586
230
  if (per_process::v8_is_profiling) {
587
    uv_loop_configure(uv_default_loop(), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
588
  }
589
#endif
590
591
460
  std::vector<char*> v8_args_as_char_ptr(v8_args.size());
592
230
  if (v8_args.size() > 0) {
593
467
    for (size_t i = 0; i < v8_args.size(); ++i)
594
237
      v8_args_as_char_ptr[i] = &v8_args[i][0];
595
230
    int argc = v8_args.size();
596
230
    V8::SetFlagsFromCommandLine(&argc, &v8_args_as_char_ptr[0], true);
597
230
    v8_args_as_char_ptr.resize(argc);
598
  }
599
600
  // Anything that's still in v8_argv is not a V8 or a node option.
601
230
  for (size_t i = 1; i < v8_args_as_char_ptr.size(); i++)
602
    errors->push_back("bad option: " + std::string(v8_args_as_char_ptr[i]));
603
604
230
  if (v8_args_as_char_ptr.size() > 1) return 9;
605
606
460
  return 0;
607
}
608
609
164
int Init(std::vector<std::string>* argv,
610
         std::vector<std::string>* exec_argv,
611
         std::vector<std::string>* errors) {
612
  // Initialize prog_start_time to get relative uptime.
613
164
  per_process::prog_start_time = static_cast<double>(uv_now(uv_default_loop()));
614
615
  // Register built-in modules
616
164
  binding::RegisterBuiltinModules();
617
618
  // Make inherited handles noninheritable.
619
164
  uv_disable_stdio_inheritance();
620
621
#ifdef NODE_REPORT
622
  // Cache the original command line to be
623
  // used in diagnostic reports.
624
164
  per_process::cli_options->cmdline = *argv;
625
#endif  //  NODE_REPORT
626
627
#if defined(NODE_V8_OPTIONS)
628
  // Should come before the call to V8::SetFlagsFromCommandLine()
629
  // so the user can disable a flag --foo at run-time by passing
630
  // --no_foo from the command line.
631
  V8::SetFlagsFromString(NODE_V8_OPTIONS, sizeof(NODE_V8_OPTIONS) - 1);
632
#endif
633
634
  std::shared_ptr<EnvironmentOptions> default_env_options =
635
164
      per_process::cli_options->per_isolate->per_env;
636
  {
637
164
    std::string text;
638
164
    default_env_options->pending_deprecation =
639

164
        credentials::SafeGetenv("NODE_PENDING_DEPRECATION", &text) &&
640
164
        text[0] == '1';
641
  }
642
643
  // Allow for environment set preserving symlinks.
644
  {
645
164
    std::string text;
646
164
    default_env_options->preserve_symlinks =
647

164
        credentials::SafeGetenv("NODE_PRESERVE_SYMLINKS", &text) &&
648
164
        text[0] == '1';
649
  }
650
651
  {
652
164
    std::string text;
653
164
    default_env_options->preserve_symlinks_main =
654

164
        credentials::SafeGetenv("NODE_PRESERVE_SYMLINKS_MAIN", &text) &&
655
164
        text[0] == '1';
656
  }
657
658
164
  if (default_env_options->redirect_warnings.empty()) {
659
    credentials::SafeGetenv("NODE_REDIRECT_WARNINGS",
660
164
                            &default_env_options->redirect_warnings);
661
  }
662
663
#if HAVE_OPENSSL
664
164
  std::string* openssl_config = &per_process::cli_options->openssl_config;
665
164
  if (openssl_config->empty()) {
666
164
    credentials::SafeGetenv("OPENSSL_CONF", openssl_config);
667
  }
668
#endif
669
670
#if !defined(NODE_WITHOUT_NODE_OPTIONS)
671
328
  std::string node_options;
672
164
  if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) {
673
    // [0] is expected to be the program name, fill it in from the real argv
674
    // and use 'x' as a placeholder while parsing.
675
66
    std::vector<std::string> env_argv = SplitString("x " + node_options, ' ');
676
66
    env_argv[0] = argv->at(0);
677
678
66
    const int exit_code = ProcessGlobalArgs(&env_argv, nullptr, errors, true);
679

66
    if (exit_code != 0) return exit_code;
680
  }
681
#endif
682
683
164
  const int exit_code = ProcessGlobalArgs(argv, exec_argv, errors, false);
684
164
  if (exit_code != 0) return exit_code;
685
686
  // Set the process.title immediately after processing argv if --title is set.
687
164
  if (!per_process::cli_options->title.empty())
688
    uv_set_process_title(per_process::cli_options->title.c_str());
689
690
#if defined(NODE_HAVE_I18N_SUPPORT)
691
  // If the parameter isn't given, use the env variable.
692
164
  if (per_process::cli_options->icu_data_dir.empty())
693
    credentials::SafeGetenv("NODE_ICU_DATA",
694
164
                            &per_process::cli_options->icu_data_dir);
695
  // Initialize ICU.
696
  // If icu_data_dir is empty here, it will load the 'minimal' data.
697
164
  if (!i18n::InitializeICUDirectory(per_process::cli_options->icu_data_dir)) {
698
    errors->push_back("could not initialize ICU "
699
                      "(check NODE_ICU_DATA or --icu-data-dir parameters)\n");
700
    return 9;
701
  }
702
164
  per_process::metadata.versions.InitializeIntlVersions();
703
#endif
704
705
  // We should set node_is_initialized here instead of in node::Start,
706
  // otherwise embedders using node::Init to initialize everything will not be
707
  // able to set it and native modules will not load for them.
708
164
  node_is_initialized = true;
709
328
  return 0;
710
}
711
712
// TODO(addaleax): Deprecate and eventually remove this.
713
void Init(int* argc,
714
          const char** argv,
715
          int* exec_argc,
716
          const char*** exec_argv) {
717
  std::vector<std::string> argv_(argv, argv + *argc);  // NOLINT
718
  std::vector<std::string> exec_argv_;
719
  std::vector<std::string> errors;
720
721
  // This (approximately) duplicates some logic that has been moved to
722
  // node::Start(), with the difference that here we explicitly call `exit()`.
723
  int exit_code = Init(&argv_, &exec_argv_, &errors);
724
725
  for (const std::string& error : errors)
726
    fprintf(stderr, "%s: %s\n", argv_.at(0).c_str(), error.c_str());
727
  if (exit_code != 0) exit(exit_code);
728
729
  if (per_process::cli_options->print_version) {
730
    printf("%s\n", NODE_VERSION);
731
    exit(0);
732
  }
733
734
  if (per_process::cli_options->print_v8_help) {
735
    V8::SetFlagsFromString("--help", 6);  // Doesn't return.
736
    UNREACHABLE();
737
  }
738
739
  *argc = argv_.size();
740
  *exec_argc = exec_argv_.size();
741
  // These leak memory, because, in the original code of this function, no
742
  // extra allocations were visible. This should be okay because this function
743
  // is only supposed to be called once per process, though.
744
  *exec_argv = Malloc<const char*>(*exec_argc);
745
  for (int i = 0; i < *exec_argc; ++i)
746
    (*exec_argv)[i] = strdup(exec_argv_[i].c_str());
747
  for (int i = 0; i < *argc; ++i)
748
    argv[i] = strdup(argv_[i].c_str());
749
}
750
751
154
void RunBeforeExit(Environment* env) {
752
154
  env->RunBeforeExitCallbacks();
753
754
154
  if (!uv_loop_alive(env->event_loop()))
755
154
    EmitBeforeExit(env);
756
154
}
757
758
164
inline int Start(Isolate* isolate, IsolateData* isolate_data,
759
                 const std::vector<std::string>& args,
760
                 const std::vector<std::string>& exec_args) {
761
164
  HandleScope handle_scope(isolate);
762
164
  Local<Context> context = NewContext(isolate);
763
  Context::Scope context_scope(context);
764
318
  Environment env(isolate_data, context, Environment::kIsMainThread);
765
164
  env.Start(per_process::v8_is_profiling);
766
164
  env.ProcessCliArgs(args, exec_args);
767
768
#if HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
769
164
  CHECK(!env.inspector_agent()->IsListening());
770
  // Inspector agent can't fail to start, but if it was configured to listen
771
  // right away on the websocket port and fails to bind/etc, this will return
772
  // false.
773
318
  env.inspector_agent()->Start(args.size() > 1 ? args[1].c_str() : "",
774
328
                               env.options()->debug_options(),
775
                               env.inspector_host_port(),
776
810
                               true);
777


164
  if (env.options()->debug_options().inspector_enabled &&
778
      !env.inspector_agent()->IsListening()) {
779
    return 12;  // Signal internal error.
780
  }
781
#else
782
  // inspector_enabled can't be true if !HAVE_INSPECTOR or !NODE_USE_V8_PLATFORM
783
  // - the option parser should not allow that.
784
  CHECK(!env.options()->debug_options().inspector_enabled);
785
#endif  // HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
786
787
  {
788
164
    Environment::AsyncCallbackScope callback_scope(&env);
789
164
    env.async_hooks()->push_async_ids(1, 0);
790
164
    LoadEnvironment(&env);
791
164
    env.async_hooks()->pop_async_id(1);
792
  }
793
794
  {
795
164
    SealHandleScope seal(isolate);
796
    bool more;
797
    env.performance_state()->Mark(
798
164
        node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_START);
799
154
    do {
800
164
      uv_run(env.event_loop(), UV_RUN_DEFAULT);
801
802
154
      per_process::v8_platform.DrainVMTasks(isolate);
803
804
154
      more = uv_loop_alive(env.event_loop());
805
154
      if (more)
806
        continue;
807
808
154
      RunBeforeExit(&env);
809
810
      // Emit `beforeExit` if the loop became alive either after emitting
811
      // event, or after running some callbacks.
812
154
      more = uv_loop_alive(env.event_loop());
813
    } while (more == true);
814
    env.performance_state()->Mark(
815
154
        node::performance::NODE_PERFORMANCE_MILESTONE_LOOP_EXIT);
816
  }
817
818
154
  env.set_trace_sync_io(false);
819
820
154
  const int exit_code = EmitExit(&env);
821
822
154
  WaitForInspectorDisconnect(&env);
823
824
154
  env.set_can_call_into_js(false);
825
154
  env.stop_sub_worker_contexts();
826
154
  uv_tty_reset_mode();
827
154
  env.RunCleanup();
828
154
  RunAtExit(&env);
829
830
154
  per_process::v8_platform.DrainVMTasks(isolate);
831
154
  per_process::v8_platform.CancelVMTasks(isolate);
832
#if defined(LEAK_SANITIZER)
833
  __lsan_do_leak_check();
834
#endif
835
836
308
  return exit_code;
837
}
838
839
164
inline int Start(uv_loop_t* event_loop,
840
                 const std::vector<std::string>& args,
841
                 const std::vector<std::string>& exec_args) {
842
  std::unique_ptr<ArrayBufferAllocator, decltype(&FreeArrayBufferAllocator)>
843
164
      allocator(CreateArrayBufferAllocator(), &FreeArrayBufferAllocator);
844
164
  Isolate* const isolate = NewIsolate(allocator.get(), event_loop);
845
164
  if (isolate == nullptr)
846
    return 12;  // Signal internal error.
847
848
164
  if (per_process::cli_options->print_version) {
849
    printf("%s\n", NODE_VERSION);
850
    return 0;
851
  }
852
853
164
  if (per_process::cli_options->print_v8_help) {
854
    V8::SetFlagsFromString("--help", 6);  // Doesn't return.
855
    UNREACHABLE();
856
  }
857
858
  {
859
164
    Mutex::ScopedLock scoped_lock(per_process::main_isolate_mutex);
860
164
    CHECK_NULL(per_process::main_isolate);
861
164
    per_process::main_isolate = isolate;
862
  }
863
864
  int exit_code;
865
  {
866
164
    Locker locker(isolate);
867
318
    Isolate::Scope isolate_scope(isolate);
868
318
    HandleScope handle_scope(isolate);
869
    std::unique_ptr<IsolateData, decltype(&FreeIsolateData)> isolate_data(
870
        CreateIsolateData(isolate,
871
                          event_loop,
872
164
                          per_process::v8_platform.Platform(),
873
                          allocator.get()),
874
482
        &FreeIsolateData);
875
    // TODO(addaleax): This should load a real per-Isolate option, currently
876
    // this is still effectively per-process.
877
164
    if (isolate_data->options()->track_heap_objects) {
878
      isolate->GetHeapProfiler()->StartTrackingHeapObjects(true);
879
    }
880
    exit_code =
881
318
        Start(isolate, isolate_data.get(), args, exec_args);
882
  }
883
884
  {
885
154
    Mutex::ScopedLock scoped_lock(per_process::main_isolate_mutex);
886
154
    CHECK_EQ(per_process::main_isolate, isolate);
887
154
    per_process::main_isolate = nullptr;
888
  }
889
890
154
  isolate->Dispose();
891
154
  per_process::v8_platform.Platform()->UnregisterIsolate(isolate);
892
893
154
  return exit_code;
894
}
895
896
164
int Start(int argc, char** argv) {
897
656
  atexit([] () { uv_tty_reset_mode(); });
898
164
  PlatformInit();
899
164
  performance::performance_node_start = PERFORMANCE_NOW();
900
901
164
  CHECK_GT(argc, 0);
902
903
#ifdef NODE_ENABLE_LARGE_CODE_PAGES
904
  if (node::IsLargePagesEnabled()) {
905
    if (node::MapStaticCodeToLargePages() != 0) {
906
      fprintf(stderr, "Reverting to default page size\n");
907
    }
908
  }
909
#endif
910
911
  // Hack around with the argv pointer. Used for process.title = "blah".
912
164
  argv = uv_setup_args(argc, argv);
913
914
164
  std::vector<std::string> args(argv, argv + argc);
915
318
  std::vector<std::string> exec_args;
916
318
  std::vector<std::string> errors;
917
  // This needs to run *before* V8::Initialize().
918
  {
919
164
    const int exit_code = Init(&args, &exec_args, &errors);
920
164
    for (const std::string& error : errors)
921
      fprintf(stderr, "%s: %s\n", args.at(0).c_str(), error.c_str());
922
164
    if (exit_code != 0) return exit_code;
923
  }
924
925
#if HAVE_OPENSSL
926
  {
927
164
    std::string extra_ca_certs;
928
164
    if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs))
929
      crypto::UseExtraCaCerts(extra_ca_certs);
930
  }
931
#ifdef NODE_FIPS_MODE
932
  // In the case of FIPS builds we should make sure
933
  // the random source is properly initialized first.
934
  OPENSSL_init();
935
#endif  // NODE_FIPS_MODE
936
  // V8 on Windows doesn't have a good source of entropy. Seed it from
937
  // OpenSSL's pool.
938
164
  V8::SetEntropySource(crypto::EntropySource);
939
#endif  // HAVE_OPENSSL
940
941
164
  InitializeV8Platform(per_process::cli_options->v8_thread_pool_size);
942
164
  V8::Initialize();
943
164
  performance::performance_v8_start = PERFORMANCE_NOW();
944
164
  per_process::v8_initialized = true;
945
  const int exit_code =
946
164
      Start(uv_default_loop(), args, exec_args);
947
154
  per_process::v8_initialized = false;
948
154
  V8::Dispose();
949
950
  // uv_run cannot be called from the time before the beforeExit callback
951
  // runs until the program exits unless the event loop has any referenced
952
  // handles after beforeExit terminates. This prevents unrefed timers
953
  // that happen to terminate during shutdown from being run unsafely.
954
  // Since uv_run cannot be called, uv_async handles held by the platform
955
  // will never be fully cleaned up.
956
154
  per_process::v8_platform.Dispose();
957
958
308
  return exit_code;
959
}
960
961

492
}  // namespace node
962
963
#if !HAVE_INSPECTOR
964
void Initialize() {}
965
966
NODE_MODULE_CONTEXT_AWARE_INTERNAL(inspector, Initialize)
967
#endif  // !HAVE_INSPECTOR