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