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