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, ¶meters, &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(¶ms,
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