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