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: 278 330 84.2 %
Date: 2019-05-05 22:32:45 Branches: 185 262 70.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.h"
27
#include "node_binding.h"
28
#include "node_internals.h"
29
#include "node_main_instance.h"
30
#include "node_metadata.h"
31
#include "node_native_module_env.h"
32
#include "node_options-inl.h"
33
#include "node_perf.h"
34
#include "node_process.h"
35
#include "node_revert.h"
36
#include "node_v8_platform-inl.h"
37
#include "node_version.h"
38
39
#if HAVE_OPENSSL
40
#include "node_crypto.h"
41
#endif
42
43
#if defined(NODE_HAVE_I18N_SUPPORT)
44
#include "node_i18n.h"
45
#endif
46
47
#if HAVE_INSPECTOR
48
#include "inspector_io.h"
49
#endif
50
51
#if defined HAVE_DTRACE || defined HAVE_ETW
52
#include "node_dtrace.h"
53
#endif
54
55
#if NODE_USE_V8_PLATFORM
56
#include "libplatform/libplatform.h"
57
#endif  // NODE_USE_V8_PLATFORM
58
#include "v8-profiler.h"
59
60
#ifdef NODE_ENABLE_VTUNE_PROFILING
61
#include "../deps/v8/src/third_party/vtune/v8-vtune.h"
62
#endif
63
64
#ifdef NODE_ENABLE_LARGE_CODE_PAGES
65
#include "large_pages/node_large_page.h"
66
#endif
67
68
#ifdef NODE_REPORT
69
#include "node_report.h"
70
#endif
71
72
// ========== global C headers ==========
73
74
#include <fcntl.h>  // _O_RDWR
75
#include <sys/types.h>
76
77
#if defined(NODE_HAVE_I18N_SUPPORT)
78
#include <unicode/uvernum.h>
79
#endif
80
81
82
#if defined(LEAK_SANITIZER)
83
#include <sanitizer/lsan_interface.h>
84
#endif
85
86
#if defined(_MSC_VER)
87
#include <direct.h>
88
#include <io.h>
89
#define STDIN_FILENO 0
90
#else
91
#include <pthread.h>
92
#include <sys/resource.h>  // getrlimit, setrlimit
93
#include <unistd.h>        // STDIN_FILENO, STDERR_FILENO
94
#endif
95
96
// ========== global C++ headers ==========
97
98
#include <cerrno>
99
#include <climits>  // PATH_MAX
100
#include <csignal>
101
#include <cstdio>
102
#include <cstdlib>
103
#include <cstring>
104
105
#include <string>
106
#include <vector>
107
108
namespace node {
109
110
using native_module::NativeModuleEnv;
111
using options_parser::kAllowedInEnvironment;
112
using options_parser::kDisallowedInEnvironment;
113
114
using v8::Boolean;
115
using v8::Context;
116
using v8::EscapableHandleScope;
117
using v8::Exception;
118
using v8::Function;
119
using v8::FunctionCallbackInfo;
120
using v8::HandleScope;
121
using v8::Isolate;
122
using v8::Local;
123
using v8::Maybe;
124
using v8::MaybeLocal;
125
using v8::Object;
126
using v8::Script;
127
using v8::String;
128
using v8::Undefined;
129
using v8::V8;
130
using v8::Value;
131
132
namespace per_process {
133
134
// node_revert.h
135
// Bit flag used to track security reverts.
136
unsigned int reverted_cve = 0;
137
138
// util.h
139
// Tells whether the per-process V8::Initialize() is called and
140
// if it is safe to call v8::Isolate::GetCurrent().
141
bool v8_initialized = false;
142
143
// node_internals.h
144
// process-relative uptime base in nanoseconds, initialized in node::Start()
145
uint64_t node_start_time;
146
// Tells whether --prof is passed.
147
bool v8_is_profiling = false;
148
149
// node_v8_platform-inl.h
150
4524
struct V8Platform v8_platform;
151
}  // namespace per_process
152
153
#ifdef __POSIX__
154
static const unsigned kMaxSignal = 32;
155
#endif
156
157
4329
void WaitForInspectorDisconnect(Environment* env) {
158
#if HAVE_INSPECTOR
159
4329
  profiler::EndStartedProfilers(env);
160
161
4329
  if (env->inspector_agent()->IsActive()) {
162
    // Restore signal dispositions, the app is done and is no longer
163
    // capable of handling signals.
164
#if defined(__POSIX__) && !defined(NODE_SHARED_MODE)
165
    struct sigaction act;
166
4325
    memset(&act, 0, sizeof(act));
167
138400
    for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
168

134075
      if (nr == SIGKILL || nr == SIGSTOP || nr == SIGPROF)
169
12975
        continue;
170
121100
      act.sa_handler = (nr == SIGPIPE) ? SIG_IGN : SIG_DFL;
171
121100
      CHECK_EQ(0, sigaction(nr, &act, nullptr));
172
    }
173
#endif
174
4325
    env->inspector_agent()->WaitForDisconnect();
175
  }
176
#endif
177
4329
}
178
179
void SignalExit(int signo) {
180
  uv_tty_reset_mode();
181
#ifdef __FreeBSD__
182
  // FreeBSD has a nasty bug, see RegisterSignalHandler for details
183
  struct sigaction sa;
184
  memset(&sa, 0, sizeof(sa));
185
  sa.sa_handler = SIG_DFL;
186
  CHECK_EQ(sigaction(signo, &sa, nullptr), 0);
187
#endif
188
  raise(signo);
189
}
190
191
13942
MaybeLocal<Value> ExecuteBootstrapper(Environment* env,
192
                                      const char* id,
193
                                      std::vector<Local<String>>* parameters,
194
                                      std::vector<Local<Value>>* arguments) {
195
13942
  EscapableHandleScope scope(env->isolate());
196
  MaybeLocal<Function> maybe_fn =
197
13942
      NativeModuleEnv::LookupAndCompile(env->context(), id, parameters, env);
198
199
13942
  if (maybe_fn.IsEmpty()) {
200
    return MaybeLocal<Value>();
201
  }
202
203
13942
  Local<Function> fn = maybe_fn.ToLocalChecked();
204
  MaybeLocal<Value> result = fn->Call(env->context(),
205
                                      Undefined(env->isolate()),
206
13942
                                      arguments->size(),
207
55768
                                      arguments->data());
208
209
  // If there was an error during bootstrap then it was either handled by the
210
  // FatalException handler or it's unrecoverable (e.g. max call stack
211
  // exceeded). Either way, clear the stack so that the AsyncCallbackScope
212
  // destructor doesn't fail on the id check.
213
  // There are only two ways to have a stack size > 1: 1) the user manually
214
  // called MakeCallback or 2) user awaited during bootstrap, which triggered
215
  // _tickCallback().
216
13733
  if (result.IsEmpty()) {
217
37
    env->async_hooks()->clear_async_id_stack();
218
  }
219
220
13733
  return scope.EscapeMaybe(result);
221
}
222
223
4650
MaybeLocal<Value> RunBootstrapping(Environment* env) {
224
4650
  CHECK(!env->has_run_bootstrapping_code());
225
226
4650
  EscapableHandleScope scope(env->isolate());
227
4650
  Isolate* isolate = env->isolate();
228
4650
  Local<Context> context = env->context();
229
230
#if HAVE_INSPECTOR
231
4650
  profiler::StartProfilers(env);
232
#endif  // HAVE_INSPECTOR
233
234
  // Add a reference to the global object
235
4650
  Local<Object> global = context->Global();
236
237
#if defined HAVE_DTRACE || defined HAVE_ETW
238
  InitDTrace(env);
239
#endif
240
241
4650
  Local<Object> process = env->process_object();
242
243
  // Setting global properties for the bootstrappers to use:
244
  // - global
245
  // Expose the global object as a property on itself
246
  // (Allows you to set stuff on `global` from anywhere in JavaScript.)
247
13950
  global->Set(context, FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global)
248
9300
      .Check();
249
250
  // Store primordials setup by the per-context script in the environment.
251
  Local<Object> per_context_bindings;
252
  Local<Value> primordials;
253

27900
  if (!GetPerContextExports(context).ToLocal(&per_context_bindings) ||
254
13950
      !per_context_bindings->Get(context, env->primordials_string())
255

37200
           .ToLocal(&primordials) ||
256
4650
      !primordials->IsObject()) {
257
    return MaybeLocal<Value>();
258
  }
259
4650
  env->set_primordials(primordials.As<Object>());
260
261
#if HAVE_INSPECTOR
262
4650
  if (env->options()->debug_options().break_node_first_line) {
263
    env->inspector_agent()->PauseOnNextJavascriptStatement(
264
        "Break at bootstrap");
265
  }
266
#endif  // HAVE_INSPECTOR
267
268
  // Create binding loaders
269
  std::vector<Local<String>> loaders_params = {
270
      env->process_string(),
271
      FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"),
272
      FIXED_ONE_BYTE_STRING(isolate, "getInternalBinding"),
273
9300
      env->primordials_string()};
274
  std::vector<Local<Value>> loaders_args = {
275
      process,
276
4650
      env->NewFunctionTemplate(binding::GetLinkedBinding)
277
13950
          ->GetFunction(context)
278
          .ToLocalChecked(),
279
4650
      env->NewFunctionTemplate(binding::GetInternalBinding)
280
13950
          ->GetFunction(context)
281
          .ToLocalChecked(),
282
27900
      env->primordials()};
283
284
  // Bootstrap internal loaders
285
  MaybeLocal<Value> loader_exports = ExecuteBootstrapper(
286
4650
      env, "internal/bootstrap/loaders", &loaders_params, &loaders_args);
287
4650
  if (loader_exports.IsEmpty()) {
288
    return MaybeLocal<Value>();
289
  }
290
291
  Local<Object> loader_exports_obj =
292
9300
      loader_exports.ToLocalChecked().As<Object>();
293
  Local<Value> internal_binding_loader =
294
13950
      loader_exports_obj->Get(context, env->internal_binding_string())
295
9300
          .ToLocalChecked();
296
4650
  env->set_internal_binding_loader(internal_binding_loader.As<Function>());
297
298
  Local<Value> require =
299
13950
      loader_exports_obj->Get(context, env->require_string()).ToLocalChecked();
300
4650
  env->set_native_module_require(require.As<Function>());
301
302
  // process, require, internalBinding, isMainThread,
303
  // ownsProcessState, primordials
304
  std::vector<Local<String>> node_params = {
305
      env->process_string(),
306
      env->require_string(),
307
      env->internal_binding_string(),
308
      FIXED_ONE_BYTE_STRING(isolate, "isMainThread"),
309
      FIXED_ONE_BYTE_STRING(isolate, "ownsProcessState"),
310
9300
      env->primordials_string()};
311
  std::vector<Local<Value>> node_args = {
312
      process,
313
      require,
314
      internal_binding_loader,
315
4650
      Boolean::New(isolate, env->is_main_thread()),
316
4650
      Boolean::New(isolate, env->owns_process_state()),
317
27900
      env->primordials()};
318
319
  MaybeLocal<Value> result = ExecuteBootstrapper(
320
4650
      env, "internal/bootstrap/node", &node_params, &node_args);
321
322
  Local<Object> env_var_proxy;
323
13950
  if (!CreateEnvVarProxy(context, isolate, env->as_callback_data())
324

32550
           .ToLocal(&env_var_proxy) ||
325
      process
326
          ->Set(env->context(),
327
                FIXED_ONE_BYTE_STRING(env->isolate(), "env"),
328

18600
                env_var_proxy)
329
23250
          .IsNothing())
330
    return MaybeLocal<Value>();
331
332
  // Make sure that no request or handle is created during bootstrap -
333
  // if necessary those should be done in pre-exeuction.
334
  // TODO(joyeecheung): print handles/requests before aborting
335
4650
  CHECK(env->req_wrap_queue()->IsEmpty());
336
4650
  CHECK(env->handle_wrap_queue()->IsEmpty());
337
338
4650
  env->set_has_run_bootstrapping_code(true);
339
340
4650
  return scope.EscapeMaybe(result);
341
}
342
343
4629
void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
344
4629
  Environment* env = Environment::GetCurrent(args);
345
  env->performance_state()->Mark(
346
4629
      performance::NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
347
4629
}
348
349
4642
MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
350
4642
  EscapableHandleScope scope(env->isolate());
351
4642
  CHECK_NOT_NULL(main_script_id);
352
353
  std::vector<Local<String>> parameters = {
354
      env->process_string(),
355
      env->require_string(),
356
      env->internal_binding_string(),
357
      env->primordials_string(),
358
9049
      FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
359
360
  std::vector<Local<Value>> arguments = {
361
      env->process_object(),
362
      env->native_module_require(),
363
      env->internal_binding_loader(),
364
      env->primordials(),
365
4642
      env->NewFunctionTemplate(MarkBootstrapComplete)
366
18568
          ->GetFunction(env->context())
367
32259
          .ToLocalChecked()};
368
369
  Local<Value> result;
370
13456
  if (!ExecuteBootstrapper(env, main_script_id, &parameters, &arguments)
371

26909
           .ToLocal(&result) ||
372
4404
      !task_queue::RunNextTicksNative(env)) {
373
43
    return MaybeLocal<Value>();
374
  }
375
4364
  return scope.Escape(result);
376
}
377
378
4468
MaybeLocal<Value> StartMainThreadExecution(Environment* env) {
379
  // To allow people to extend Node in different ways, this hook allows
380
  // one to drop a file lib/_third_party_main.js into the build
381
  // directory which will be executed instead of Node's normal loading.
382
4468
  if (NativeModuleEnv::Exists("_third_party_main")) {
383
    return StartExecution(env, "internal/main/run_third_party_main");
384
  }
385
386
4468
  std::string first_argv;
387
4468
  if (env->argv().size() > 1) {
388
4135
    first_argv = env->argv()[1];
389
  }
390
391

4468
  if (first_argv == "inspect" || first_argv == "debug") {
392
4
    return StartExecution(env, "internal/main/inspect");
393
  }
394
395
4464
  if (per_process::cli_options->print_help) {
396
1
    return StartExecution(env, "internal/main/print_help");
397
  }
398
399
4463
  if (per_process::cli_options->print_bash_completion) {
400
1
    return StartExecution(env, "internal/main/print_bash_completion");
401
  }
402
403
4462
  if (env->options()->prof_process) {
404
77
    return StartExecution(env, "internal/main/prof_process");
405
  }
406
407
  // -e/--eval without -i/--interactive
408


4385
  if (env->options()->has_eval_string && !env->options()->force_repl) {
409
310
    return StartExecution(env, "internal/main/eval_string");
410
  }
411
412
4075
  if (env->options()->syntax_check_only) {
413
34
    return StartExecution(env, "internal/main/check_syntax");
414
  }
415
416

4041
  if (!first_argv.empty() && first_argv != "-") {
417
4012
    return StartExecution(env, "internal/main/run_main_module");
418
  }
419
420


29
  if (env->options()->force_repl || uv_guess_handle(STDIN_FILENO) == UV_TTY) {
421
12
    return StartExecution(env, "internal/main/repl");
422
  }
423
424
17
  return StartExecution(env, "internal/main/eval_stdin");
425
}
426
427
4468
void LoadEnvironment(Environment* env) {
428
4468
  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
4468
  USE(StartMainThreadExecution(env));
434
4233
}
435
436
437
#ifdef __POSIX__
438
13701
void RegisterSignalHandler(int signal,
439
                           void (*handler)(int signal),
440
                           bool reset_handler) {
441
  struct sigaction sa;
442
13701
  memset(&sa, 0, sizeof(sa));
443
13701
  sa.sa_handler = handler;
444
#ifndef __FreeBSD__
445
  // FreeBSD has a nasty bug with SA_RESETHAND reseting the SA_SIGINFO, that is
446
  // in turn set for a libthr wrapper. This leads to a crash.
447
  // Work around the issue by manually setting SIG_DFL in the signal handler
448
13701
  sa.sa_flags = reset_handler ? SA_RESETHAND : 0;
449
#endif
450
13701
  sigfillset(&sa.sa_mask);
451
13701
  CHECK_EQ(sigaction(signal, &sa, nullptr), 0);
452
13701
}
453
454
#endif  // __POSIX__
455
456
4523
inline void PlatformInit() {
457
#ifdef __POSIX__
458
#if HAVE_INSPECTOR
459
  sigset_t sigmask;
460
4523
  sigemptyset(&sigmask);
461
4523
  sigaddset(&sigmask, SIGUSR1);
462
4523
  const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
463
#endif  // HAVE_INSPECTOR
464
465
  // Make sure file descriptors 0-2 are valid before we start logging anything.
466
18092
  for (int fd = STDIN_FILENO; fd <= STDERR_FILENO; fd += 1) {
467
    struct stat ignored;
468
13569
    if (fstat(fd, &ignored) == 0)
469
13567
      continue;
470
    // Anything but EBADF means something is seriously wrong.  We don't
471
    // have to special-case EINTR, fstat() is not interruptible.
472
2
    if (errno != EBADF)
473
      ABORT();
474
2
    if (fd != open("/dev/null", O_RDWR))
475
      ABORT();
476
  }
477
478
#if HAVE_INSPECTOR
479
4523
  CHECK_EQ(err, 0);
480
#endif  // HAVE_INSPECTOR
481
482
#ifndef NODE_SHARED_MODE
483
  // Restore signal dispositions, the parent process may have changed them.
484
  struct sigaction act;
485
4523
  memset(&act, 0, sizeof(act));
486
487
  // The hard-coded upper limit is because NSIG is not very reliable; on Linux,
488
  // it evaluates to 32, 34 or 64, depending on whether RT signals are enabled.
489
  // Counting up to SIGRTMIN doesn't work for the same reason.
490
144736
  for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
491

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

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


53031
                "--abort-on-uncaught-exception") != v8_args.end() ||
567
      std::find(v8_args.begin(), v8_args.end(),
568

35337
                "--abort_on_uncaught_exception") != v8_args.end()) {
569
20
    env_opts->abort_on_uncaught_exception = true;
570
  }
571
572
  // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler
573
  // manually?  That would give us a little more control over its runtime
574
  // behavior but it could also interfere with the user's intentions in ways
575
  // we fail to anticipate.  Dillema.
576
8847
  if (std::find(v8_args.begin(), v8_args.end(), "--prof") != v8_args.end()) {
577
2
    per_process::v8_is_profiling = true;
578
  }
579
580
#ifdef __POSIX__
581
  // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc.  Avoids the
582
  // performance penalty of frequent EINTR wakeups when the profiler is running.
583
  // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
584
8847
  if (per_process::v8_is_profiling) {
585
2
    uv_loop_configure(uv_default_loop(), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
586
  }
587
#endif
588
589
17694
  std::vector<char*> v8_args_as_char_ptr(v8_args.size());
590
8847
  if (v8_args.size() > 0) {
591
17810
    for (size_t i = 0; i < v8_args.size(); ++i)
592
8963
      v8_args_as_char_ptr[i] = &v8_args[i][0];
593
8847
    int argc = v8_args.size();
594
8847
    V8::SetFlagsFromCommandLine(&argc, &v8_args_as_char_ptr[0], true);
595
8847
    v8_args_as_char_ptr.resize(argc);
596
  }
597
598
  // Anything that's still in v8_argv is not a V8 or a node option.
599
8860
  for (size_t i = 1; i < v8_args_as_char_ptr.size(); i++)
600
13
    errors->push_back("bad option: " + std::string(v8_args_as_char_ptr[i]));
601
602
8847
  if (v8_args_as_char_ptr.size() > 1) return 9;
603
604
17720
  return 0;
605
}
606
607
static std::atomic_bool init_called{false};
608
609
4523
int InitializeNodeWithArgs(std::vector<std::string>* argv,
610
                           std::vector<std::string>* exec_argv,
611
                           std::vector<std::string>* errors) {
612
  // Make sure InitializeNodeWithArgs() is called only once.
613
4523
  CHECK(!init_called.exchange(true));
614
615
  // Register built-in modules
616
4523
  binding::RegisterBuiltinModules();
617
618
  // Make inherited handles noninheritable.
619
4523
  uv_disable_stdio_inheritance();
620
621
#ifdef NODE_REPORT
622
  // Cache the original command line to be
623
  // used in diagnostic reports.
624
4523
  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
4523
      per_process::cli_options->per_isolate->per_env;
636
  {
637
4523
    std::string text;
638
4523
    default_env_options->pending_deprecation =
639

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

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

4523
        credentials::SafeGetenv("NODE_PRESERVE_SYMLINKS_MAIN", &text) &&
655
4523
        text[0] == '1';
656
  }
657
658
4523
  if (default_env_options->redirect_warnings.empty()) {
659
    credentials::SafeGetenv("NODE_REDIRECT_WARNINGS",
660
4523
                            &default_env_options->redirect_warnings);
661
  }
662
663
#if HAVE_OPENSSL
664
4523
  std::string* openssl_config = &per_process::cli_options->openssl_config;
665
4523
  if (openssl_config->empty()) {
666
4523
    credentials::SafeGetenv("OPENSSL_CONF", openssl_config);
667
  }
668
#endif
669
670
#if !defined(NODE_WITHOUT_NODE_OPTIONS)
671
9046
  std::string node_options;
672
673
4523
  if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) {
674
4376
    std::vector<std::string> env_argv;
675
    // [0] is expected to be the program name, fill it in from the real argv.
676
4376
    env_argv.push_back(argv->at(0));
677
678
4376
    bool is_in_string = false;
679
4376
    bool will_start_new_arg = true;
680
13438
    for (std::string::size_type index = 0;
681
6719
         index < node_options.size();
682
         ++index) {
683
2343
      char c = node_options.at(index);
684
685
      // Backslashes escape the following character
686

2343
      if (c == '\\' && is_in_string) {
687
        if (index + 1 == node_options.size()) {
688
          errors->push_back("invalid value for NODE_OPTIONS "
689
                            "(invalid escape)\n");
690
          return 9;
691
        } else {
692
          c = node_options.at(++index);
693
        }
694

2343
      } else if (c == ' ' && !is_in_string) {
695
43
        will_start_new_arg = true;
696
43
        continue;
697
2300
      } else if (c == '"') {
698
4
        is_in_string = !is_in_string;
699
4
        continue;
700
      }
701
702
2296
      if (will_start_new_arg) {
703
90
        env_argv.push_back(std::string(1, c));
704
90
        will_start_new_arg = false;
705
      } else {
706
2206
        env_argv.back() += c;
707
      }
708
    }
709
710
4376
    if (is_in_string) {
711
      errors->push_back("invalid value for NODE_OPTIONS "
712
                        "(unterminated string)\n");
713
      return 9;
714
    }
715
716
4376
    const int exit_code = ProcessGlobalArgs(&env_argv, nullptr, errors, true);
717

4376
    if (exit_code != 0) return exit_code;
718
  }
719
#endif
720
721
4508
  const int exit_code = ProcessGlobalArgs(argv, exec_argv, errors, false);
722
4508
  if (exit_code != 0) return exit_code;
723
724
  // Set the process.title immediately after processing argv if --title is set.
725
4475
  if (!per_process::cli_options->title.empty())
726
2
    uv_set_process_title(per_process::cli_options->title.c_str());
727
728
#if defined(NODE_HAVE_I18N_SUPPORT)
729
  // If the parameter isn't given, use the env variable.
730
4475
  if (per_process::cli_options->icu_data_dir.empty())
731
    credentials::SafeGetenv("NODE_ICU_DATA",
732
4474
                            &per_process::cli_options->icu_data_dir);
733
  // Initialize ICU.
734
  // If icu_data_dir is empty here, it will load the 'minimal' data.
735
4475
  if (!i18n::InitializeICUDirectory(per_process::cli_options->icu_data_dir)) {
736
    errors->push_back("could not initialize ICU "
737
2
                      "(check NODE_ICU_DATA or --icu-data-dir parameters)\n");
738
2
    return 9;
739
  }
740
4473
  per_process::metadata.versions.InitializeIntlVersions();
741
#endif
742
743
4473
  NativeModuleEnv::InitializeCodeCache();
744
745
  // We should set node_is_initialized here instead of in node::Start,
746
  // otherwise embedders using node::Init to initialize everything will not be
747
  // able to set it and native modules will not load for them.
748
4473
  node_is_initialized = true;
749
8996
  return 0;
750
}
751
752
// TODO(addaleax): Deprecate and eventually remove this.
753
void Init(int* argc,
754
          const char** argv,
755
          int* exec_argc,
756
          const char*** exec_argv) {
757
  std::vector<std::string> argv_(argv, argv + *argc);  // NOLINT
758
  std::vector<std::string> exec_argv_;
759
  std::vector<std::string> errors;
760
761
  // This (approximately) duplicates some logic that has been moved to
762
  // node::Start(), with the difference that here we explicitly call `exit()`.
763
  int exit_code = InitializeNodeWithArgs(&argv_, &exec_argv_, &errors);
764
765
  for (const std::string& error : errors)
766
    fprintf(stderr, "%s: %s\n", argv_.at(0).c_str(), error.c_str());
767
  if (exit_code != 0) exit(exit_code);
768
769
  if (per_process::cli_options->print_version) {
770
    printf("%s\n", NODE_VERSION);
771
    exit(0);
772
  }
773
774
  if (per_process::cli_options->print_v8_help) {
775
    V8::SetFlagsFromString("--help", 6);  // Doesn't return.
776
    UNREACHABLE();
777
  }
778
779
  *argc = argv_.size();
780
  *exec_argc = exec_argv_.size();
781
  // These leak memory, because, in the original code of this function, no
782
  // extra allocations were visible. This should be okay because this function
783
  // is only supposed to be called once per process, though.
784
  *exec_argv = Malloc<const char*>(*exec_argc);
785
  for (int i = 0; i < *exec_argc; ++i)
786
    (*exec_argv)[i] = strdup(exec_argv_[i].c_str());
787
  for (int i = 0; i < *argc; ++i)
788
    argv[i] = strdup(argv_[i].c_str());
789
}
790
791
4523
InitializationResult InitializeOncePerProcess(int argc, char** argv) {
792
18092
  atexit([] () { uv_tty_reset_mode(); });
793
4523
  PlatformInit();
794
4523
  per_process::node_start_time = uv_hrtime();
795
796
4523
  CHECK_GT(argc, 0);
797
798
#ifdef NODE_ENABLE_LARGE_CODE_PAGES
799
  if (node::IsLargePagesEnabled()) {
800
    if (node::MapStaticCodeToLargePages() != 0) {
801
      fprintf(stderr, "Reverting to default page size\n");
802
    }
803
  }
804
#endif
805
806
  // Hack around with the argv pointer. Used for process.title = "blah".
807
4523
  argv = uv_setup_args(argc, argv);
808
809
4523
  InitializationResult result;
810
4523
  result.args = std::vector<std::string>(argv, argv + argc);
811
9045
  std::vector<std::string> errors;
812
813
  // This needs to run *before* V8::Initialize().
814
  {
815
    result.exit_code =
816
4523
        InitializeNodeWithArgs(&(result.args), &(result.exec_args), &errors);
817
4575
    for (const std::string& error : errors)
818
52
      fprintf(stderr, "%s: %s\n", result.args.at(0).c_str(), error.c_str());
819
4523
    if (result.exit_code != 0) {
820
50
      result.early_return = true;
821
50
      return result;
822
    }
823
  }
824
825
4473
  if (per_process::cli_options->print_version) {
826
3
    printf("%s\n", NODE_VERSION);
827
3
    result.exit_code = 0;
828
3
    result.early_return = true;
829
3
    return result;
830
  }
831
832
4470
  if (per_process::cli_options->print_v8_help) {
833
1
    V8::SetFlagsFromString("--help", 6);  // Doesn't return.
834
    UNREACHABLE();
835
  }
836
837
#if HAVE_OPENSSL
838
  {
839
4469
    std::string extra_ca_certs;
840
4469
    if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs))
841
3
      crypto::UseExtraCaCerts(extra_ca_certs);
842
  }
843
#ifdef NODE_FIPS_MODE
844
  // In the case of FIPS builds we should make sure
845
  // the random source is properly initialized first.
846
  OPENSSL_init();
847
#endif  // NODE_FIPS_MODE
848
  // V8 on Windows doesn't have a good source of entropy. Seed it from
849
  // OpenSSL's pool.
850
4469
  V8::SetEntropySource(crypto::EntropySource);
851
#endif  // HAVE_OPENSSL
852
853
4469
  InitializeV8Platform(per_process::cli_options->v8_thread_pool_size);
854
4469
  V8::Initialize();
855
4469
  performance::performance_v8_start = PERFORMANCE_NOW();
856
4469
  per_process::v8_initialized = true;
857
4469
  return result;
858
}
859
860
4089
void TearDownOncePerProcess() {
861
4089
  per_process::v8_initialized = false;
862
4089
  V8::Dispose();
863
864
  // uv_run cannot be called from the time before the beforeExit callback
865
  // runs until the program exits unless the event loop has any referenced
866
  // handles after beforeExit terminates. This prevents unrefed timers
867
  // that happen to terminate during shutdown from being run unsafely.
868
  // Since uv_run cannot be called, uv_async handles held by the platform
869
  // will never be fully cleaned up.
870
4089
  per_process::v8_platform.Dispose();
871
4089
}
872
873
4523
int Start(int argc, char** argv) {
874
4523
  InitializationResult result = InitializeOncePerProcess(argc, argv);
875
4522
  if (result.early_return) {
876
53
    return result.exit_code;
877
  }
878
879
  {
880
4469
    Isolate::CreateParams params;
881
    // TODO(joyeecheung): collect external references and set it in
882
    // params.external_references.
883
    std::vector<intptr_t> external_references = {
884
4469
        reinterpret_cast<intptr_t>(nullptr)};
885
4469
    v8::StartupData* blob = NodeMainInstance::GetEmbeddedSnapshotBlob();
886
    const std::vector<size_t>* indexes =
887
4469
        NodeMainInstance::GetIsolateDataIndexes();
888
4469
    if (blob != nullptr) {
889
      params.external_references = external_references.data();
890
      params.snapshot_blob = blob;
891
    }
892
893
    NodeMainInstance main_instance(&params,
894
                                   uv_default_loop(),
895
4469
                                   per_process::v8_platform.Platform(),
896
                                   result.args,
897
                                   result.exec_args,
898
8558
                                   indexes);
899
8558
    result.exit_code = main_instance.Run();
900
  }
901
902
4089
  TearDownOncePerProcess();
903
4089
  return result.exit_code;
904
}
905
906
63
int Stop(Environment* env) {
907
63
  env->ExitEnv();
908
63
  return 0;
909
}
910
911

13572
}  // namespace node
912
913
#if !HAVE_INSPECTOR
914
void Initialize() {}
915
916
NODE_MODULE_CONTEXT_AWARE_INTERNAL(inspector, Initialize)
917
#endif  // !HAVE_INSPECTOR