• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "memory_tracker-inl.h"
29 #include "histogram-inl.h"
30 #include "node_binding.h"
31 #include "node_errors.h"
32 #include "node_internals.h"
33 #include "node_main_instance.h"
34 #include "node_metadata.h"
35 #include "node_native_module_env.h"
36 #include "node_options-inl.h"
37 #include "node_perf.h"
38 #include "node_process-inl.h"
39 #include "node_report.h"
40 #include "node_revert.h"
41 #include "node_v8_platform-inl.h"
42 #include "node_version.h"
43 
44 #if HAVE_OPENSSL
45 #include "allocated_buffer-inl.h"  // Inlined functions needed by node_crypto.h
46 #include "node_crypto.h"
47 #endif
48 
49 #if defined(NODE_HAVE_I18N_SUPPORT)
50 #include "node_i18n.h"
51 #endif
52 
53 #if HAVE_INSPECTOR
54 #include "inspector_agent.h"
55 #include "inspector_io.h"
56 #endif
57 
58 #if defined HAVE_DTRACE || defined HAVE_ETW
59 #include "node_dtrace.h"
60 #endif
61 
62 #if NODE_USE_V8_PLATFORM
63 #include "libplatform/libplatform.h"
64 #endif  // NODE_USE_V8_PLATFORM
65 #include "v8-profiler.h"
66 
67 #if HAVE_INSPECTOR
68 #include "inspector/worker_inspector.h"  // ParentInspectorHandle
69 #endif
70 
71 #include "large_pages/node_large_page.h"
72 
73 #if defined(__APPLE__) || defined(__linux__)
74 #define NODE_USE_V8_WASM_TRAP_HANDLER 1
75 #else
76 #define NODE_USE_V8_WASM_TRAP_HANDLER 0
77 #endif
78 
79 #if NODE_USE_V8_WASM_TRAP_HANDLER
80 #include <atomic>
81 #include "v8-wasm-trap-handler-posix.h"
82 #endif  // NODE_USE_V8_WASM_TRAP_HANDLER
83 
84 // ========== global C headers ==========
85 
86 #include <fcntl.h>  // _O_RDWR
87 #include <sys/types.h>
88 
89 #if defined(NODE_HAVE_I18N_SUPPORT)
90 #include <unicode/uvernum.h>
91 #include <unicode/utypes.h>
92 #endif
93 
94 
95 #if defined(LEAK_SANITIZER)
96 #include <sanitizer/lsan_interface.h>
97 #endif
98 
99 #if defined(_MSC_VER)
100 #include <direct.h>
101 #include <io.h>
102 #define STDIN_FILENO 0
103 #else
104 #include <pthread.h>
105 #include <sys/resource.h>  // getrlimit, setrlimit
106 #include <termios.h>       // tcgetattr, tcsetattr
107 #include <unistd.h>        // STDIN_FILENO, STDERR_FILENO
108 #endif
109 
110 // ========== global C++ headers ==========
111 
112 #include <cerrno>
113 #include <climits>  // PATH_MAX
114 #include <csignal>
115 #include <cstdio>
116 #include <cstdlib>
117 #include <cstring>
118 
119 #include <string>
120 #include <vector>
121 
122 namespace node {
123 
124 using native_module::NativeModuleEnv;
125 
126 using v8::EscapableHandleScope;
127 using v8::Function;
128 using v8::FunctionCallbackInfo;
129 using v8::Isolate;
130 using v8::Local;
131 using v8::MaybeLocal;
132 using v8::Object;
133 using v8::String;
134 using v8::Undefined;
135 using v8::V8;
136 using v8::Value;
137 
138 namespace per_process {
139 
140 // node_revert.h
141 // Bit flag used to track security reverts.
142 unsigned int reverted_cve = 0;
143 
144 // util.h
145 // Tells whether the per-process V8::Initialize() is called and
146 // if it is safe to call v8::Isolate::GetCurrent().
147 bool v8_initialized = false;
148 
149 // node_internals.h
150 // process-relative uptime base in nanoseconds, initialized in node::Start()
151 uint64_t node_start_time;
152 
153 // node_v8_platform-inl.h
154 struct V8Platform v8_platform;
155 }  // namespace per_process
156 
157 #ifdef __POSIX__
SignalExit(int signo,siginfo_t * info,void * ucontext)158 void SignalExit(int signo, siginfo_t* info, void* ucontext) {
159   ResetStdio();
160   raise(signo);
161 }
162 #endif  // __POSIX__
163 
ExecuteBootstrapper(Environment * env,const char * id,std::vector<Local<String>> * parameters,std::vector<Local<Value>> * arguments)164 MaybeLocal<Value> ExecuteBootstrapper(Environment* env,
165                                       const char* id,
166                                       std::vector<Local<String>>* parameters,
167                                       std::vector<Local<Value>>* arguments) {
168   EscapableHandleScope scope(env->isolate());
169   MaybeLocal<Function> maybe_fn =
170       NativeModuleEnv::LookupAndCompile(env->context(), id, parameters, env);
171 
172   Local<Function> fn;
173   if (!maybe_fn.ToLocal(&fn)) {
174     return MaybeLocal<Value>();
175   }
176 
177   MaybeLocal<Value> result = fn->Call(env->context(),
178                                       Undefined(env->isolate()),
179                                       arguments->size(),
180                                       arguments->data());
181 
182   // If there was an error during bootstrap, it must be unrecoverable
183   // (e.g. max call stack exceeded). Clear the stack so that the
184   // AsyncCallbackScope destructor doesn't fail on the id check.
185   // There are only two ways to have a stack size > 1: 1) the user manually
186   // called MakeCallback or 2) user awaited during bootstrap, which triggered
187   // _tickCallback().
188   if (result.IsEmpty()) {
189     env->async_hooks()->clear_async_id_stack();
190   }
191 
192   return scope.EscapeMaybe(result);
193 }
194 
195 #if HAVE_INSPECTOR
InitializeInspector(std::unique_ptr<inspector::ParentInspectorHandle> parent_handle)196 int Environment::InitializeInspector(
197     std::unique_ptr<inspector::ParentInspectorHandle> parent_handle) {
198   std::string inspector_path;
199   bool is_main = !parent_handle;
200   if (parent_handle) {
201     inspector_path = parent_handle->url();
202     inspector_agent_->SetParentHandle(std::move(parent_handle));
203   } else {
204     inspector_path = argv_.size() > 1 ? argv_[1].c_str() : "";
205   }
206 
207   CHECK(!inspector_agent_->IsListening());
208   // Inspector agent can't fail to start, but if it was configured to listen
209   // right away on the websocket port and fails to bind/etc, this will return
210   // false.
211   inspector_agent_->Start(inspector_path,
212                           options_->debug_options(),
213                           inspector_host_port(),
214                           is_main);
215   if (options_->debug_options().inspector_enabled &&
216       !inspector_agent_->IsListening()) {
217     return 12;  // Signal internal error
218   }
219 
220   profiler::StartProfilers(this);
221 
222   if (inspector_agent_->options().break_node_first_line) {
223     inspector_agent_->PauseOnNextJavascriptStatement("Break at bootstrap");
224   }
225 
226   return 0;
227 }
228 #endif  // HAVE_INSPECTOR && NODE_USE_V8_PLATFORM
229 
230 #define ATOMIC_WAIT_EVENTS(V)                                               \
231   V(kStartWait,           "started")                                        \
232   V(kWokenUp,             "was woken up by another thread")                 \
233   V(kTimedOut,            "timed out")                                      \
234   V(kTerminatedExecution, "was stopped by terminated execution")            \
235   V(kAPIStopped,          "was stopped through the embedder API")           \
236   V(kNotEqual,            "did not wait because the values mismatched")     \
237 
AtomicsWaitCallback(Isolate::AtomicsWaitEvent event,Local<v8::SharedArrayBuffer> array_buffer,size_t offset_in_bytes,int64_t value,double timeout_in_ms,Isolate::AtomicsWaitWakeHandle * stop_handle,void * data)238 static void AtomicsWaitCallback(Isolate::AtomicsWaitEvent event,
239                                 Local<v8::SharedArrayBuffer> array_buffer,
240                                 size_t offset_in_bytes, int64_t value,
241                                 double timeout_in_ms,
242                                 Isolate::AtomicsWaitWakeHandle* stop_handle,
243                                 void* data) {
244   Environment* env = static_cast<Environment*>(data);
245 
246   const char* message = "(unknown event)";
247   switch (event) {
248 #define V(key, msg)                         \
249     case Isolate::AtomicsWaitEvent::key:    \
250       message = msg;                        \
251       break;
252     ATOMIC_WAIT_EVENTS(V)
253 #undef V
254   }
255 
256   fprintf(stderr,
257           "(node:%d) [Thread %" PRIu64 "] Atomics.wait(%p + %zx, %" PRId64
258               ", %.f) %s\n",
259           static_cast<int>(uv_os_getpid()),
260           env->thread_id(),
261           array_buffer->GetBackingStore()->Data(),
262           offset_in_bytes,
263           value,
264           timeout_in_ms,
265           message);
266 }
267 
InitializeDiagnostics()268 void Environment::InitializeDiagnostics() {
269   isolate_->GetHeapProfiler()->AddBuildEmbedderGraphCallback(
270       Environment::BuildEmbedderGraph, this);
271   if (options_->heap_snapshot_near_heap_limit > 0) {
272     isolate_->AddNearHeapLimitCallback(Environment::NearHeapLimitCallback,
273                                        this);
274   }
275   if (options_->trace_uncaught)
276     isolate_->SetCaptureStackTraceForUncaughtExceptions(true);
277   if (options_->trace_atomics_wait) {
278     isolate_->SetAtomicsWaitCallback(AtomicsWaitCallback, this);
279     AddCleanupHook([](void* data) {
280       Environment* env = static_cast<Environment*>(data);
281       env->isolate()->SetAtomicsWaitCallback(nullptr, nullptr);
282     }, this);
283   }
284 
285 #if defined HAVE_DTRACE || defined HAVE_ETW
286   InitDTrace(this);
287 #endif
288 }
289 
BootstrapInternalLoaders()290 MaybeLocal<Value> Environment::BootstrapInternalLoaders() {
291   EscapableHandleScope scope(isolate_);
292 
293   // Create binding loaders
294   std::vector<Local<String>> loaders_params = {
295       process_string(),
296       FIXED_ONE_BYTE_STRING(isolate_, "getLinkedBinding"),
297       FIXED_ONE_BYTE_STRING(isolate_, "getInternalBinding"),
298       primordials_string()};
299   std::vector<Local<Value>> loaders_args = {
300       process_object(),
301       NewFunctionTemplate(binding::GetLinkedBinding)
302           ->GetFunction(context())
303           .ToLocalChecked(),
304       NewFunctionTemplate(binding::GetInternalBinding)
305           ->GetFunction(context())
306           .ToLocalChecked(),
307       primordials()};
308 
309   // Bootstrap internal loaders
310   Local<Value> loader_exports;
311   if (!ExecuteBootstrapper(
312            this, "internal/bootstrap/loaders", &loaders_params, &loaders_args)
313            .ToLocal(&loader_exports)) {
314     return MaybeLocal<Value>();
315   }
316   CHECK(loader_exports->IsObject());
317   Local<Object> loader_exports_obj = loader_exports.As<Object>();
318   Local<Value> internal_binding_loader =
319       loader_exports_obj->Get(context(), internal_binding_string())
320           .ToLocalChecked();
321   CHECK(internal_binding_loader->IsFunction());
322   set_internal_binding_loader(internal_binding_loader.As<Function>());
323   Local<Value> require =
324       loader_exports_obj->Get(context(), require_string()).ToLocalChecked();
325   CHECK(require->IsFunction());
326   set_native_module_require(require.As<Function>());
327 
328   return scope.Escape(loader_exports);
329 }
330 
BootstrapNode()331 MaybeLocal<Value> Environment::BootstrapNode() {
332   EscapableHandleScope scope(isolate_);
333 
334   Local<Object> global = context()->Global();
335   // TODO(joyeecheung): this can be done in JS land now.
336   global->Set(context(), FIXED_ONE_BYTE_STRING(isolate_, "global"), global)
337       .Check();
338 
339   // process, require, internalBinding, primordials
340   std::vector<Local<String>> node_params = {
341       process_string(),
342       require_string(),
343       internal_binding_string(),
344       primordials_string()};
345   std::vector<Local<Value>> node_args = {
346       process_object(),
347       native_module_require(),
348       internal_binding_loader(),
349       primordials()};
350 
351   MaybeLocal<Value> result = ExecuteBootstrapper(
352       this, "internal/bootstrap/node", &node_params, &node_args);
353 
354   if (result.IsEmpty()) {
355     return scope.EscapeMaybe(result);
356   }
357 
358   auto thread_switch_id =
359       is_main_thread() ? "internal/bootstrap/switches/is_main_thread"
360                        : "internal/bootstrap/switches/is_not_main_thread";
361   result =
362       ExecuteBootstrapper(this, thread_switch_id, &node_params, &node_args);
363 
364   if (result.IsEmpty()) {
365     return scope.EscapeMaybe(result);
366   }
367 
368   auto process_state_switch_id =
369       owns_process_state()
370           ? "internal/bootstrap/switches/does_own_process_state"
371           : "internal/bootstrap/switches/does_not_own_process_state";
372   result = ExecuteBootstrapper(
373       this, process_state_switch_id, &node_params, &node_args);
374 
375   if (result.IsEmpty()) {
376     return scope.EscapeMaybe(result);
377   }
378 
379   Local<String> env_string = FIXED_ONE_BYTE_STRING(isolate_, "env");
380   Local<Object> env_var_proxy;
381   if (!CreateEnvVarProxy(context(), isolate_).ToLocal(&env_var_proxy) ||
382       process_object()->Set(context(), env_string, env_var_proxy).IsNothing()) {
383     return MaybeLocal<Value>();
384   }
385 
386   return scope.EscapeMaybe(result);
387 }
388 
RunBootstrapping()389 MaybeLocal<Value> Environment::RunBootstrapping() {
390   EscapableHandleScope scope(isolate_);
391 
392   CHECK(!has_run_bootstrapping_code());
393 
394   if (BootstrapInternalLoaders().IsEmpty()) {
395     return MaybeLocal<Value>();
396   }
397 
398   Local<Value> result;
399   if (!BootstrapNode().ToLocal(&result)) {
400     return MaybeLocal<Value>();
401   }
402 
403   // Make sure that no request or handle is created during bootstrap -
404   // if necessary those should be done in pre-execution.
405   // Usually, doing so would trigger the checks present in the ReqWrap and
406   // HandleWrap classes, so this is only a consistency check.
407   CHECK(req_wrap_queue()->IsEmpty());
408   CHECK(handle_wrap_queue()->IsEmpty());
409 
410   set_has_run_bootstrapping_code(true);
411 
412   return scope.Escape(result);
413 }
414 
MarkBootstrapComplete(const FunctionCallbackInfo<Value> & args)415 void MarkBootstrapComplete(const FunctionCallbackInfo<Value>& args) {
416   Environment* env = Environment::GetCurrent(args);
417   env->performance_state()->Mark(
418       performance::NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
419 }
420 
421 static
StartExecution(Environment * env,const char * main_script_id)422 MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
423   EscapableHandleScope scope(env->isolate());
424   CHECK_NOT_NULL(main_script_id);
425 
426   std::vector<Local<String>> parameters = {
427       env->process_string(),
428       env->require_string(),
429       env->internal_binding_string(),
430       env->primordials_string(),
431       FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
432 
433   std::vector<Local<Value>> arguments = {
434       env->process_object(),
435       env->native_module_require(),
436       env->internal_binding_loader(),
437       env->primordials(),
438       env->NewFunctionTemplate(MarkBootstrapComplete)
439           ->GetFunction(env->context())
440           .ToLocalChecked()};
441 
442   return scope.EscapeMaybe(
443       ExecuteBootstrapper(env, main_script_id, &parameters, &arguments));
444 }
445 
StartExecution(Environment * env,StartExecutionCallback cb)446 MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
447   InternalCallbackScope callback_scope(
448       env,
449       Object::New(env->isolate()),
450       { 1, 0 },
451       InternalCallbackScope::kSkipAsyncHooks);
452 
453   if (cb != nullptr) {
454     EscapableHandleScope scope(env->isolate());
455 
456     if (StartExecution(env, "internal/bootstrap/environment").IsEmpty())
457       return {};
458 
459     StartExecutionCallbackInfo info = {
460       env->process_object(),
461       env->native_module_require(),
462     };
463 
464     return scope.EscapeMaybe(cb(info));
465   }
466 
467   // To allow people to extend Node in different ways, this hook allows
468   // one to drop a file lib/_third_party_main.js into the build
469   // directory which will be executed instead of Node's normal loading.
470   if (NativeModuleEnv::Exists("_third_party_main")) {
471     return StartExecution(env, "internal/main/run_third_party_main");
472   }
473 
474   if (env->worker_context() != nullptr) {
475     return StartExecution(env, "internal/main/worker_thread");
476   }
477 
478   std::string first_argv;
479   if (env->argv().size() > 1) {
480     first_argv = env->argv()[1];
481   }
482 
483   if (first_argv == "inspect" || first_argv == "debug") {
484     return StartExecution(env, "internal/main/inspect");
485   }
486 
487   if (per_process::cli_options->print_help) {
488     return StartExecution(env, "internal/main/print_help");
489   }
490 
491 
492   if (env->options()->prof_process) {
493     return StartExecution(env, "internal/main/prof_process");
494   }
495 
496   // -e/--eval without -i/--interactive
497   if (env->options()->has_eval_string && !env->options()->force_repl) {
498     return StartExecution(env, "internal/main/eval_string");
499   }
500 
501   if (env->options()->syntax_check_only) {
502     return StartExecution(env, "internal/main/check_syntax");
503   }
504 
505   if (!first_argv.empty() && first_argv != "-") {
506     return StartExecution(env, "internal/main/run_main_module");
507   }
508 
509   if (env->options()->force_repl || uv_guess_handle(STDIN_FILENO) == UV_TTY) {
510     return StartExecution(env, "internal/main/repl");
511   }
512 
513   return StartExecution(env, "internal/main/eval_stdin");
514 }
515 
516 #ifdef __POSIX__
517 typedef void (*sigaction_cb)(int signo, siginfo_t* info, void* ucontext);
518 #endif
519 #if NODE_USE_V8_WASM_TRAP_HANDLER
520 static std::atomic<sigaction_cb> previous_sigsegv_action;
521 
TrapWebAssemblyOrContinue(int signo,siginfo_t * info,void * ucontext)522 void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) {
523   if (!v8::TryHandleWebAssemblyTrapPosix(signo, info, ucontext)) {
524     sigaction_cb prev = previous_sigsegv_action.load();
525     if (prev != nullptr) {
526       prev(signo, info, ucontext);
527     } else {
528       // Reset to the default signal handler, i.e. cause a hard crash.
529       struct sigaction sa;
530       memset(&sa, 0, sizeof(sa));
531       sa.sa_handler = SIG_DFL;
532       CHECK_EQ(sigaction(signo, &sa, nullptr), 0);
533 
534       ResetStdio();
535       raise(signo);
536     }
537   }
538 }
539 #endif  // NODE_USE_V8_WASM_TRAP_HANDLER
540 
541 #ifdef __POSIX__
RegisterSignalHandler(int signal,sigaction_cb handler,bool reset_handler)542 void RegisterSignalHandler(int signal,
543                            sigaction_cb handler,
544                            bool reset_handler) {
545   CHECK_NOT_NULL(handler);
546 #if NODE_USE_V8_WASM_TRAP_HANDLER
547   if (signal == SIGSEGV) {
548     CHECK(previous_sigsegv_action.is_lock_free());
549     CHECK(!reset_handler);
550     previous_sigsegv_action.store(handler);
551     return;
552   }
553 #endif  // NODE_USE_V8_WASM_TRAP_HANDLER
554   struct sigaction sa;
555   memset(&sa, 0, sizeof(sa));
556   sa.sa_sigaction = handler;
557   sa.sa_flags = reset_handler ? SA_RESETHAND : 0;
558   sigfillset(&sa.sa_mask);
559   CHECK_EQ(sigaction(signal, &sa, nullptr), 0);
560 }
561 
562 #endif  // __POSIX__
563 
564 #ifdef __POSIX__
565 static struct {
566   int flags;
567   bool isatty;
568   struct stat stat;
569   struct termios termios;
570 } stdio[1 + STDERR_FILENO];
571 #endif  // __POSIX__
572 
573 
PlatformInit()574 inline void PlatformInit() {
575 #ifdef __POSIX__
576 #if HAVE_INSPECTOR
577   sigset_t sigmask;
578   sigemptyset(&sigmask);
579   sigaddset(&sigmask, SIGUSR1);
580   const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr);
581 #endif  // HAVE_INSPECTOR
582 
583   // Make sure file descriptors 0-2 are valid before we start logging anything.
584   for (auto& s : stdio) {
585     const int fd = &s - stdio;
586     if (fstat(fd, &s.stat) == 0)
587       continue;
588     // Anything but EBADF means something is seriously wrong.  We don't
589     // have to special-case EINTR, fstat() is not interruptible.
590     if (errno != EBADF)
591       ABORT();
592     if (fd != open("/dev/null", O_RDWR))
593       ABORT();
594     if (fstat(fd, &s.stat) != 0)
595       ABORT();
596   }
597 
598 #if HAVE_INSPECTOR
599   CHECK_EQ(err, 0);
600 #endif  // HAVE_INSPECTOR
601 
602   // TODO(addaleax): NODE_SHARED_MODE does not really make sense here.
603 #ifndef NODE_SHARED_MODE
604   // Restore signal dispositions, the parent process may have changed them.
605   struct sigaction act;
606   memset(&act, 0, sizeof(act));
607 
608   // The hard-coded upper limit is because NSIG is not very reliable; on Linux,
609   // it evaluates to 32, 34 or 64, depending on whether RT signals are enabled.
610   // Counting up to SIGRTMIN doesn't work for the same reason.
611   for (unsigned nr = 1; nr < kMaxSignal; nr += 1) {
612     if (nr == SIGKILL || nr == SIGSTOP)
613       continue;
614     act.sa_handler = (nr == SIGPIPE || nr == SIGXFSZ) ? SIG_IGN : SIG_DFL;
615     CHECK_EQ(0, sigaction(nr, &act, nullptr));
616   }
617 #endif  // !NODE_SHARED_MODE
618 
619   // Record the state of the stdio file descriptors so we can restore it
620   // on exit.  Needs to happen before installing signal handlers because
621   // they make use of that information.
622   for (auto& s : stdio) {
623     const int fd = &s - stdio;
624     int err;
625 
626     do
627       s.flags = fcntl(fd, F_GETFL);
628     while (s.flags == -1 && errno == EINTR);  // NOLINT
629     CHECK_NE(s.flags, -1);
630 
631     if (uv_guess_handle(fd) != UV_TTY) continue;
632     s.isatty = true;
633 
634     do
635       err = tcgetattr(fd, &s.termios);
636     while (err == -1 && errno == EINTR);  // NOLINT
637     CHECK_EQ(err, 0);
638   }
639 
640   RegisterSignalHandler(SIGINT, SignalExit, true);
641   RegisterSignalHandler(SIGTERM, SignalExit, true);
642 
643 #if NODE_USE_V8_WASM_TRAP_HANDLER
644   // Tell V8 to disable emitting WebAssembly
645   // memory bounds checks. This means that we have
646   // to catch the SIGSEGV in TrapWebAssemblyOrContinue
647   // and pass the signal context to V8.
648   {
649     struct sigaction sa;
650     memset(&sa, 0, sizeof(sa));
651     sa.sa_sigaction = TrapWebAssemblyOrContinue;
652     sa.sa_flags = SA_SIGINFO;
653     CHECK_EQ(sigaction(SIGSEGV, &sa, nullptr), 0);
654   }
655   V8::EnableWebAssemblyTrapHandler(false);
656 #endif  // NODE_USE_V8_WASM_TRAP_HANDLER
657 
658   // Raise the open file descriptor limit.
659   struct rlimit lim;
660   if (getrlimit(RLIMIT_NOFILE, &lim) == 0 && lim.rlim_cur != lim.rlim_max) {
661     // Do a binary search for the limit.
662     rlim_t min = lim.rlim_cur;
663     rlim_t max = 1 << 20;
664     // But if there's a defined upper bound, don't search, just set it.
665     if (lim.rlim_max != RLIM_INFINITY) {
666       min = lim.rlim_max;
667       max = lim.rlim_max;
668     }
669     do {
670       lim.rlim_cur = min + (max - min) / 2;
671       if (setrlimit(RLIMIT_NOFILE, &lim)) {
672         max = lim.rlim_cur;
673       } else {
674         min = lim.rlim_cur;
675       }
676     } while (min + 1 < max);
677   }
678 #endif  // __POSIX__
679 #ifdef _WIN32
680   for (int fd = 0; fd <= 2; ++fd) {
681     auto handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
682     if (handle == INVALID_HANDLE_VALUE ||
683         GetFileType(handle) == FILE_TYPE_UNKNOWN) {
684       // Ignore _close result. If it fails or not depends on used Windows
685       // version. We will just check _open result.
686       _close(fd);
687       if (fd != _open("nul", _O_RDWR))
688         ABORT();
689     }
690   }
691 #endif  // _WIN32
692 }
693 
694 
695 // Safe to call more than once and from signal handlers.
ResetStdio()696 void ResetStdio() {
697   uv_tty_reset_mode();
698 #ifdef __POSIX__
699   for (auto& s : stdio) {
700     const int fd = &s - stdio;
701 
702     struct stat tmp;
703     if (-1 == fstat(fd, &tmp)) {
704       CHECK_EQ(errno, EBADF);  // Program closed file descriptor.
705       continue;
706     }
707 
708     bool is_same_file =
709         (s.stat.st_dev == tmp.st_dev && s.stat.st_ino == tmp.st_ino);
710     if (!is_same_file) continue;  // Program reopened file descriptor.
711 
712     int flags;
713     do
714       flags = fcntl(fd, F_GETFL);
715     while (flags == -1 && errno == EINTR);  // NOLINT
716     CHECK_NE(flags, -1);
717 
718     // Restore the O_NONBLOCK flag if it changed.
719     if (O_NONBLOCK & (flags ^ s.flags)) {
720       flags &= ~O_NONBLOCK;
721       flags |= s.flags & O_NONBLOCK;
722 
723       int err;
724       do
725         err = fcntl(fd, F_SETFL, flags);
726       while (err == -1 && errno == EINTR);  // NOLINT
727       CHECK_NE(err, -1);
728     }
729 
730     if (s.isatty) {
731       sigset_t sa;
732       int err;
733 
734       // We might be a background job that doesn't own the TTY so block SIGTTOU
735       // before making the tcsetattr() call, otherwise that signal suspends us.
736       sigemptyset(&sa);
737       sigaddset(&sa, SIGTTOU);
738 
739       CHECK_EQ(0, pthread_sigmask(SIG_BLOCK, &sa, nullptr));
740       do
741         err = tcsetattr(fd, TCSANOW, &s.termios);
742       while (err == -1 && errno == EINTR);  // NOLINT
743       CHECK_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sa, nullptr));
744 
745       // Normally we expect err == 0. But if macOS App Sandbox is enabled,
746       // tcsetattr will fail with err == -1 and errno == EPERM.
747       CHECK_IMPLIES(err != 0, err == -1 && errno == EPERM);
748     }
749   }
750 #endif  // __POSIX__
751 }
752 
753 
ProcessGlobalArgs(std::vector<std::string> * args,std::vector<std::string> * exec_args,std::vector<std::string> * errors,OptionEnvvarSettings settings)754 int ProcessGlobalArgs(std::vector<std::string>* args,
755                       std::vector<std::string>* exec_args,
756                       std::vector<std::string>* errors,
757                       OptionEnvvarSettings settings) {
758   // Parse a few arguments which are specific to Node.
759   std::vector<std::string> v8_args;
760 
761   Mutex::ScopedLock lock(per_process::cli_options_mutex);
762   options_parser::Parse(
763       args,
764       exec_args,
765       &v8_args,
766       per_process::cli_options.get(),
767       settings,
768       errors);
769 
770   if (!errors->empty()) return 9;
771 
772   std::string revert_error;
773   for (const std::string& cve : per_process::cli_options->security_reverts) {
774     Revert(cve.c_str(), &revert_error);
775     if (!revert_error.empty()) {
776       errors->emplace_back(std::move(revert_error));
777       return 12;
778     }
779   }
780 
781   if (per_process::cli_options->disable_proto != "delete" &&
782       per_process::cli_options->disable_proto != "throw" &&
783       per_process::cli_options->disable_proto != "") {
784     errors->emplace_back("invalid mode passed to --disable-proto");
785     return 12;
786   }
787 
788   // TODO(mylesborins): remove this when the harmony-top-level-await flag
789   // is removed in V8
790   if (std::find(v8_args.begin(), v8_args.end(),
791                 "--no-harmony-top-level-await") == v8_args.end()) {
792     v8_args.push_back("--harmony-top-level-await");
793   }
794 
795   auto env_opts = per_process::cli_options->per_isolate->per_env;
796   if (std::find(v8_args.begin(), v8_args.end(),
797                 "--abort-on-uncaught-exception") != v8_args.end() ||
798       std::find(v8_args.begin(), v8_args.end(),
799                 "--abort_on_uncaught_exception") != v8_args.end()) {
800     env_opts->abort_on_uncaught_exception = true;
801   }
802 
803 #ifdef __POSIX__
804   // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc.  Avoids the
805   // performance penalty of frequent EINTR wakeups when the profiler is running.
806   // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
807   if (std::find(v8_args.begin(), v8_args.end(), "--prof") != v8_args.end()) {
808     uv_loop_configure(uv_default_loop(), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
809   }
810 #endif
811 
812   std::vector<char*> v8_args_as_char_ptr(v8_args.size());
813   if (v8_args.size() > 0) {
814     for (size_t i = 0; i < v8_args.size(); ++i)
815       v8_args_as_char_ptr[i] = &v8_args[i][0];
816     int argc = v8_args.size();
817     V8::SetFlagsFromCommandLine(&argc, &v8_args_as_char_ptr[0], true);
818     v8_args_as_char_ptr.resize(argc);
819   }
820 
821   // Anything that's still in v8_argv is not a V8 or a node option.
822   for (size_t i = 1; i < v8_args_as_char_ptr.size(); i++)
823     errors->push_back("bad option: " + std::string(v8_args_as_char_ptr[i]));
824 
825   if (v8_args_as_char_ptr.size() > 1) return 9;
826 
827   return 0;
828 }
829 
830 static std::atomic_bool init_called{false};
831 
InitializeNodeWithArgs(std::vector<std::string> * argv,std::vector<std::string> * exec_argv,std::vector<std::string> * errors)832 int InitializeNodeWithArgs(std::vector<std::string>* argv,
833                            std::vector<std::string>* exec_argv,
834                            std::vector<std::string>* errors) {
835   // Make sure InitializeNodeWithArgs() is called only once.
836   CHECK(!init_called.exchange(true));
837 
838   // Initialize node_start_time to get relative uptime.
839   per_process::node_start_time = uv_hrtime();
840 
841   // Register built-in modules
842   binding::RegisterBuiltinModules();
843 
844   // Make inherited handles noninheritable.
845   uv_disable_stdio_inheritance();
846 
847   // Cache the original command line to be
848   // used in diagnostic reports.
849   per_process::cli_options->cmdline = *argv;
850 
851 #if defined(NODE_V8_OPTIONS)
852   // Should come before the call to V8::SetFlagsFromCommandLine()
853   // so the user can disable a flag --foo at run-time by passing
854   // --no_foo from the command line.
855   V8::SetFlagsFromString(NODE_V8_OPTIONS, sizeof(NODE_V8_OPTIONS) - 1);
856 #endif
857 
858   HandleEnvOptions(per_process::cli_options->per_isolate->per_env);
859 
860 #if !defined(NODE_WITHOUT_NODE_OPTIONS)
861   std::string node_options;
862 
863   if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) {
864     std::vector<std::string> env_argv =
865         ParseNodeOptionsEnvVar(node_options, errors);
866 
867     if (!errors->empty()) return 9;
868 
869     // [0] is expected to be the program name, fill it in from the real argv.
870     env_argv.insert(env_argv.begin(), argv->at(0));
871 
872     const int exit_code = ProcessGlobalArgs(&env_argv,
873                                             nullptr,
874                                             errors,
875                                             kAllowedInEnvironment);
876     if (exit_code != 0) return exit_code;
877   }
878 #endif
879 
880   const int exit_code = ProcessGlobalArgs(argv,
881                                           exec_argv,
882                                           errors,
883                                           kDisallowedInEnvironment);
884   if (exit_code != 0) return exit_code;
885 
886   // Set the process.title immediately after processing argv if --title is set.
887   if (!per_process::cli_options->title.empty())
888     uv_set_process_title(per_process::cli_options->title.c_str());
889 
890 #if defined(NODE_HAVE_I18N_SUPPORT)
891   // If the parameter isn't given, use the env variable.
892   if (per_process::cli_options->icu_data_dir.empty())
893     credentials::SafeGetenv("NODE_ICU_DATA",
894                             &per_process::cli_options->icu_data_dir);
895 
896 #ifdef NODE_ICU_DEFAULT_DATA_DIR
897   // If neither the CLI option nor the environment variable was specified,
898   // fall back to the configured default
899   if (per_process::cli_options->icu_data_dir.empty()) {
900     // Check whether the NODE_ICU_DEFAULT_DATA_DIR contains the right data
901     // file and can be read.
902     static const char full_path[] =
903         NODE_ICU_DEFAULT_DATA_DIR "/" U_ICUDATA_NAME ".dat";
904 
905     FILE* f = fopen(full_path, "rb");
906 
907     if (f != nullptr) {
908       fclose(f);
909       per_process::cli_options->icu_data_dir = NODE_ICU_DEFAULT_DATA_DIR;
910     }
911   }
912 #endif  // NODE_ICU_DEFAULT_DATA_DIR
913 
914   // Initialize ICU.
915   // If icu_data_dir is empty here, it will load the 'minimal' data.
916   if (!i18n::InitializeICUDirectory(per_process::cli_options->icu_data_dir)) {
917     errors->push_back("could not initialize ICU "
918                       "(check NODE_ICU_DATA or --icu-data-dir parameters)\n");
919     return 9;
920   }
921   per_process::metadata.versions.InitializeIntlVersions();
922 #endif
923 
924   NativeModuleEnv::InitializeCodeCache();
925 
926   // We should set node_is_initialized here instead of in node::Start,
927   // otherwise embedders using node::Init to initialize everything will not be
928   // able to set it and native modules will not load for them.
929   node_is_initialized = true;
930   return 0;
931 }
932 
933 // TODO(addaleax): Deprecate and eventually remove this.
Init(int * argc,const char ** argv,int * exec_argc,const char *** exec_argv)934 void Init(int* argc,
935           const char** argv,
936           int* exec_argc,
937           const char*** exec_argv) {
938   std::vector<std::string> argv_(argv, argv + *argc);  // NOLINT
939   std::vector<std::string> exec_argv_;
940   std::vector<std::string> errors;
941 
942   // This (approximately) duplicates some logic that has been moved to
943   // node::Start(), with the difference that here we explicitly call `exit()`.
944   int exit_code = InitializeNodeWithArgs(&argv_, &exec_argv_, &errors);
945 
946   for (const std::string& error : errors)
947     fprintf(stderr, "%s: %s\n", argv_.at(0).c_str(), error.c_str());
948   if (exit_code != 0) exit(exit_code);
949 
950   if (per_process::cli_options->print_version) {
951     printf("%s\n", NODE_VERSION);
952     exit(0);
953   }
954 
955   if (per_process::cli_options->print_bash_completion) {
956     std::string completion = options_parser::GetBashCompletion();
957     printf("%s\n", completion.c_str());
958     exit(0);
959   }
960 
961   if (per_process::cli_options->print_v8_help) {
962     V8::SetFlagsFromString("--help", static_cast<size_t>(6));
963     exit(0);
964   }
965 
966   *argc = argv_.size();
967   *exec_argc = exec_argv_.size();
968   // These leak memory, because, in the original code of this function, no
969   // extra allocations were visible. This should be okay because this function
970   // is only supposed to be called once per process, though.
971   *exec_argv = Malloc<const char*>(*exec_argc);
972   for (int i = 0; i < *exec_argc; ++i)
973     (*exec_argv)[i] = strdup(exec_argv_[i].c_str());
974   for (int i = 0; i < *argc; ++i)
975     argv[i] = strdup(argv_[i].c_str());
976 }
977 
InitializeOncePerProcess(int argc,char ** argv)978 InitializationResult InitializeOncePerProcess(int argc, char** argv) {
979   // Initialized the enabled list for Debug() calls with system
980   // environment variables.
981   per_process::enabled_debug_list.Parse(nullptr);
982 
983   atexit(ResetStdio);
984   PlatformInit();
985 
986   CHECK_GT(argc, 0);
987 
988   // Hack around with the argv pointer. Used for process.title = "blah".
989   argv = uv_setup_args(argc, argv);
990 
991   InitializationResult result;
992   result.args = std::vector<std::string>(argv, argv + argc);
993   std::vector<std::string> errors;
994 
995   // This needs to run *before* V8::Initialize().
996   {
997     result.exit_code =
998         InitializeNodeWithArgs(&(result.args), &(result.exec_args), &errors);
999     for (const std::string& error : errors)
1000       fprintf(stderr, "%s: %s\n", result.args.at(0).c_str(), error.c_str());
1001     if (result.exit_code != 0) {
1002       result.early_return = true;
1003       return result;
1004     }
1005   }
1006 
1007   if (per_process::cli_options->use_largepages == "on" ||
1008       per_process::cli_options->use_largepages == "silent") {
1009     int result = node::MapStaticCodeToLargePages();
1010     if (per_process::cli_options->use_largepages == "on" && result != 0) {
1011       fprintf(stderr, "%s\n", node::LargePagesError(result));
1012     }
1013   }
1014 
1015   if (per_process::cli_options->print_version) {
1016     printf("%s\n", NODE_VERSION);
1017     result.exit_code = 0;
1018     result.early_return = true;
1019     return result;
1020   }
1021 
1022   if (per_process::cli_options->print_bash_completion) {
1023     std::string completion = options_parser::GetBashCompletion();
1024     printf("%s\n", completion.c_str());
1025     result.exit_code = 0;
1026     result.early_return = true;
1027     return result;
1028   }
1029 
1030   if (per_process::cli_options->print_v8_help) {
1031     V8::SetFlagsFromString("--help", static_cast<size_t>(6));
1032     result.exit_code = 0;
1033     result.early_return = true;
1034     return result;
1035   }
1036 
1037 #if HAVE_OPENSSL
1038   {
1039     std::string extra_ca_certs;
1040     if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs))
1041       crypto::UseExtraCaCerts(extra_ca_certs);
1042   }
1043   // In the case of FIPS builds we should make sure
1044   // the random source is properly initialized first.
1045   if (FIPS_mode()) {
1046     OPENSSL_init();
1047   }
1048   // V8 on Windows doesn't have a good source of entropy. Seed it from
1049   // OpenSSL's pool.
1050   V8::SetEntropySource(crypto::EntropySource);
1051 #endif  // HAVE_OPENSSL
1052 
1053   per_process::v8_platform.Initialize(
1054       per_process::cli_options->v8_thread_pool_size);
1055   V8::Initialize();
1056   performance::performance_v8_start = PERFORMANCE_NOW();
1057   per_process::v8_initialized = true;
1058   return result;
1059 }
1060 
TearDownOncePerProcess()1061 void TearDownOncePerProcess() {
1062   per_process::v8_initialized = false;
1063   V8::Dispose();
1064 
1065   // uv_run cannot be called from the time before the beforeExit callback
1066   // runs until the program exits unless the event loop has any referenced
1067   // handles after beforeExit terminates. This prevents unrefed timers
1068   // that happen to terminate during shutdown from being run unsafely.
1069   // Since uv_run cannot be called, uv_async handles held by the platform
1070   // will never be fully cleaned up.
1071   per_process::v8_platform.Dispose();
1072 }
1073 
Start(int argc,char ** argv)1074 int Start(int argc, char** argv) {
1075   InitializationResult result = InitializeOncePerProcess(argc, argv);
1076   if (result.early_return) {
1077     return result.exit_code;
1078   }
1079 
1080   {
1081     Isolate::CreateParams params;
1082     const std::vector<size_t>* indexes = nullptr;
1083     std::vector<intptr_t> external_references;
1084 
1085     bool use_no_snapshot =
1086         per_process::cli_options->per_isolate->node_snapshot;
1087     if (use_no_snapshot) {
1088       v8::StartupData* blob = NodeMainInstance::GetEmbeddedSnapshotBlob();
1089       if (blob != nullptr) {
1090         // TODO(joyeecheung): collect external references and set it in
1091         // params.external_references.
1092         external_references.push_back(reinterpret_cast<intptr_t>(nullptr));
1093         params.external_references = external_references.data();
1094         params.snapshot_blob = blob;
1095         indexes = NodeMainInstance::GetIsolateDataIndexes();
1096       }
1097     }
1098     uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME);
1099 
1100     NodeMainInstance main_instance(&params,
1101                                    uv_default_loop(),
1102                                    per_process::v8_platform.Platform(),
1103                                    result.args,
1104                                    result.exec_args,
1105                                    indexes);
1106     result.exit_code = main_instance.Run();
1107   }
1108 
1109   TearDownOncePerProcess();
1110   return result.exit_code;
1111 }
1112 
Stop(Environment * env)1113 int Stop(Environment* env) {
1114   env->ExitEnv();
1115   return 0;
1116 }
1117 
1118 }  // namespace node
1119 
1120 #if !HAVE_INSPECTOR
Initialize()1121 void Initialize() {}
1122 
1123 NODE_MODULE_CONTEXT_AWARE_INTERNAL(inspector, Initialize)
1124 #endif  // !HAVE_INSPECTOR
1125