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