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 "histogram-inl.h" 29#include "memory_tracker-inl.h" 30#include "node_binding.h" 31#include "node_builtins.h" 32#include "node_errors.h" 33#include "node_internals.h" 34#include "node_main_instance.h" 35#include "node_metadata.h" 36#include "node_options-inl.h" 37#include "node_perf.h" 38#include "node_process-inl.h" 39#include "node_realm-inl.h" 40#include "node_report.h" 41#include "node_revert.h" 42#include "node_sea.h" 43#include "node_snapshot_builder.h" 44#include "node_v8_platform-inl.h" 45#include "node_version.h" 46 47#if HAVE_OPENSSL 48#include "node_crypto.h" 49#endif 50 51#if defined(NODE_HAVE_I18N_SUPPORT) 52#include "node_i18n.h" 53#endif 54 55#if HAVE_INSPECTOR 56#include "inspector_agent.h" 57#include "inspector_io.h" 58#endif 59 60#if defined HAVE_DTRACE || defined HAVE_ETW 61#include "node_dtrace.h" 62#endif 63 64#if NODE_USE_V8_PLATFORM 65#include "libplatform/libplatform.h" 66#endif // NODE_USE_V8_PLATFORM 67#include "v8-profiler.h" 68 69#if HAVE_INSPECTOR 70#include "inspector/worker_inspector.h" // ParentInspectorHandle 71#endif 72 73#ifdef NODE_ENABLE_VTUNE_PROFILING 74#include "../deps/v8/src/third_party/vtune/v8-vtune.h" 75#endif 76 77#include "large_pages/node_large_page.h" 78 79#if defined(__APPLE__) || defined(__linux__) || defined(_WIN32) 80#define NODE_USE_V8_WASM_TRAP_HANDLER 1 81#else 82#define NODE_USE_V8_WASM_TRAP_HANDLER 0 83#endif 84 85#if NODE_USE_V8_WASM_TRAP_HANDLER 86#if defined(_WIN32) 87#include "v8-wasm-trap-handler-win.h" 88#else 89#include <atomic> 90#include "v8-wasm-trap-handler-posix.h" 91#endif 92#endif // NODE_USE_V8_WASM_TRAP_HANDLER 93 94// ========== global C headers ========== 95 96#include <fcntl.h> // _O_RDWR 97#include <sys/types.h> 98 99#if defined(NODE_HAVE_I18N_SUPPORT) 100#include <unicode/uvernum.h> 101#include <unicode/utypes.h> 102#endif 103 104 105#if defined(LEAK_SANITIZER) 106#include <sanitizer/lsan_interface.h> 107#endif 108 109#if defined(_MSC_VER) 110#include <direct.h> 111#include <io.h> 112#define STDIN_FILENO 0 113#else 114#include <pthread.h> 115#include <sys/resource.h> // getrlimit, setrlimit 116#include <termios.h> // tcgetattr, tcsetattr 117#include <unistd.h> // STDIN_FILENO, STDERR_FILENO 118#endif 119 120// ========== global C++ headers ========== 121 122#include <cerrno> 123#include <climits> // PATH_MAX 124#include <csignal> 125#include <cstdio> 126#include <cstdlib> 127#include <cstring> 128 129#include <string> 130#include <tuple> 131#include <vector> 132 133namespace node { 134 135using v8::EscapableHandleScope; 136using v8::Isolate; 137using v8::Local; 138using v8::MaybeLocal; 139using v8::Object; 140using v8::V8; 141using v8::Value; 142 143namespace per_process { 144 145// node_revert.h 146// Bit flag used to track security reverts. 147unsigned int reverted_cve = 0; 148 149// util.h 150// Tells whether the per-process V8::Initialize() is called and 151// if it is safe to call v8::Isolate::TryGetCurrent(). 152bool v8_initialized = false; 153 154// node_internals.h 155// process-relative uptime base in nanoseconds, initialized in node::Start() 156uint64_t node_start_time; 157 158#if NODE_USE_V8_WASM_TRAP_HANDLER && defined(_WIN32) 159PVOID old_vectored_exception_handler; 160#endif 161 162// node_v8_platform-inl.h 163struct V8Platform v8_platform; 164} // namespace per_process 165 166// The section in the OpenSSL configuration file to be loaded. 167const char* conf_section_name = STRINGIFY(NODE_OPENSSL_CONF_NAME); 168 169#ifdef __POSIX__ 170void SignalExit(int signo, siginfo_t* info, void* ucontext) { 171 ResetStdio(); 172 raise(signo); 173} 174#endif // __POSIX__ 175 176#if HAVE_INSPECTOR 177int Environment::InitializeInspector( 178 std::unique_ptr<inspector::ParentInspectorHandle> parent_handle) { 179 std::string inspector_path; 180 bool is_main = !parent_handle; 181 if (parent_handle) { 182 inspector_path = parent_handle->url(); 183 inspector_agent_->SetParentHandle(std::move(parent_handle)); 184 } else { 185 inspector_path = argv_.size() > 1 ? argv_[1].c_str() : ""; 186 } 187 188 CHECK(!inspector_agent_->IsListening()); 189 // Inspector agent can't fail to start, but if it was configured to listen 190 // right away on the websocket port and fails to bind/etc, this will return 191 // false. 192 inspector_agent_->Start(inspector_path, 193 options_->debug_options(), 194 inspector_host_port(), 195 is_main); 196 if (options_->debug_options().inspector_enabled && 197 !inspector_agent_->IsListening()) { 198 return 12; // Signal internal error 199 } 200 201 profiler::StartProfilers(this); 202 203 if (inspector_agent_->options().break_node_first_line) { 204 inspector_agent_->PauseOnNextJavascriptStatement("Break at bootstrap"); 205 } 206 207 return 0; 208} 209#endif // HAVE_INSPECTOR 210 211#define ATOMIC_WAIT_EVENTS(V) \ 212 V(kStartWait, "started") \ 213 V(kWokenUp, "was woken up by another thread") \ 214 V(kTimedOut, "timed out") \ 215 V(kTerminatedExecution, "was stopped by terminated execution") \ 216 V(kAPIStopped, "was stopped through the embedder API") \ 217 V(kNotEqual, "did not wait because the values mismatched") \ 218 219static void AtomicsWaitCallback(Isolate::AtomicsWaitEvent event, 220 Local<v8::SharedArrayBuffer> array_buffer, 221 size_t offset_in_bytes, int64_t value, 222 double timeout_in_ms, 223 Isolate::AtomicsWaitWakeHandle* stop_handle, 224 void* data) { 225 Environment* env = static_cast<Environment*>(data); 226 227 const char* message = "(unknown event)"; 228 switch (event) { 229#define V(key, msg) \ 230 case Isolate::AtomicsWaitEvent::key: \ 231 message = msg; \ 232 break; 233 ATOMIC_WAIT_EVENTS(V) 234#undef V 235 } 236 237 fprintf(stderr, 238 "(node:%d) [Thread %" PRIu64 "] Atomics.wait(%p + %zx, %" PRId64 239 ", %.f) %s\n", 240 static_cast<int>(uv_os_getpid()), 241 env->thread_id(), 242 array_buffer->Data(), 243 offset_in_bytes, 244 value, 245 timeout_in_ms, 246 message); 247} 248 249void Environment::InitializeDiagnostics() { 250 isolate_->GetHeapProfiler()->AddBuildEmbedderGraphCallback( 251 Environment::BuildEmbedderGraph, this); 252 if (heap_snapshot_near_heap_limit_ > 0) { 253 AddHeapSnapshotNearHeapLimitCallback(); 254 } 255 if (options_->trace_uncaught) 256 isolate_->SetCaptureStackTraceForUncaughtExceptions(true); 257 if (options_->trace_atomics_wait) { 258 isolate_->SetAtomicsWaitCallback(AtomicsWaitCallback, this); 259 AddCleanupHook([](void* data) { 260 Environment* env = static_cast<Environment*>(data); 261 env->isolate()->SetAtomicsWaitCallback(nullptr, nullptr); 262 }, this); 263 } 264 265#if defined HAVE_DTRACE || defined HAVE_ETW 266 InitDTrace(this); 267#endif 268} 269 270static 271MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) { 272 EscapableHandleScope scope(env->isolate()); 273 CHECK_NOT_NULL(main_script_id); 274 Realm* realm = env->principal_realm(); 275 276 return scope.EscapeMaybe(realm->ExecuteBootstrapper(main_script_id)); 277} 278 279MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) { 280 InternalCallbackScope callback_scope( 281 env, 282 Object::New(env->isolate()), 283 { 1, 0 }, 284 InternalCallbackScope::kSkipAsyncHooks); 285 286 if (cb != nullptr) { 287 EscapableHandleScope scope(env->isolate()); 288 289 if (StartExecution(env, "internal/main/environment").IsEmpty()) return {}; 290 291 StartExecutionCallbackInfo info = { 292 env->process_object(), 293 env->builtin_module_require(), 294 }; 295 296 return scope.EscapeMaybe(cb(info)); 297 } 298 299 // TODO(joyeecheung): move these conditions into JS land and let the 300 // deserialize main function take precedence. For workers, we need to 301 // move the pre-execution part into a different file that can be 302 // reused when dealing with user-defined main functions. 303 if (!env->snapshot_deserialize_main().IsEmpty()) { 304 return env->RunSnapshotDeserializeMain(); 305 } 306 307 if (env->worker_context() != nullptr) { 308 return StartExecution(env, "internal/main/worker_thread"); 309 } 310 311 std::string first_argv; 312 if (env->argv().size() > 1) { 313 first_argv = env->argv()[1]; 314 } 315 316#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION 317 if (sea::IsSingleExecutable()) { 318 // TODO(addaleax): Find a way to reuse: 319 // 320 // LoadEnvironment(Environment*, const char*) 321 // 322 // instead and not add yet another main entry point here because this 323 // already duplicates existing code. 324 return StartExecution(env, "internal/main/single_executable_application"); 325 } 326#endif 327 328 if (first_argv == "inspect") { 329 return StartExecution(env, "internal/main/inspect"); 330 } 331 332 if (per_process::cli_options->build_snapshot) { 333 return StartExecution(env, "internal/main/mksnapshot"); 334 } 335 336 if (per_process::cli_options->print_help) { 337 return StartExecution(env, "internal/main/print_help"); 338 } 339 340 341 if (env->options()->prof_process) { 342 return StartExecution(env, "internal/main/prof_process"); 343 } 344 345 // -e/--eval without -i/--interactive 346 if (env->options()->has_eval_string && !env->options()->force_repl) { 347 return StartExecution(env, "internal/main/eval_string"); 348 } 349 350 if (env->options()->syntax_check_only) { 351 return StartExecution(env, "internal/main/check_syntax"); 352 } 353 354 if (env->options()->test_runner) { 355 return StartExecution(env, "internal/main/test_runner"); 356 } 357 358 if (env->options()->watch_mode) { 359 return StartExecution(env, "internal/main/watch_mode"); 360 } 361 362 if (!first_argv.empty() && first_argv != "-") { 363 return StartExecution(env, "internal/main/run_main_module"); 364 } 365 366 if (env->options()->force_repl || uv_guess_handle(STDIN_FILENO) == UV_TTY) { 367 return StartExecution(env, "internal/main/repl"); 368 } 369 370 return StartExecution(env, "internal/main/eval_stdin"); 371} 372 373#ifdef __POSIX__ 374typedef void (*sigaction_cb)(int signo, siginfo_t* info, void* ucontext); 375#endif 376#if NODE_USE_V8_WASM_TRAP_HANDLER 377#if defined(_WIN32) 378static LONG TrapWebAssemblyOrContinue(EXCEPTION_POINTERS* exception) { 379 if (v8::TryHandleWebAssemblyTrapWindows(exception)) { 380 return EXCEPTION_CONTINUE_EXECUTION; 381 } 382 return EXCEPTION_CONTINUE_SEARCH; 383} 384#else 385static std::atomic<sigaction_cb> previous_sigsegv_action; 386// TODO(align behavior between macos and other in next major version) 387#if defined(__APPLE__) 388static std::atomic<sigaction_cb> previous_sigbus_action; 389#endif // __APPLE__ 390 391void TrapWebAssemblyOrContinue(int signo, siginfo_t* info, void* ucontext) { 392 if (!v8::TryHandleWebAssemblyTrapPosix(signo, info, ucontext)) { 393#if defined(__APPLE__) 394 sigaction_cb prev = signo == SIGBUS ? previous_sigbus_action.load() 395 : previous_sigsegv_action.load(); 396#else 397 sigaction_cb prev = previous_sigsegv_action.load(); 398#endif // __APPLE__ 399 if (prev != nullptr) { 400 prev(signo, info, ucontext); 401 } else { 402 // Reset to the default signal handler, i.e. cause a hard crash. 403 struct sigaction sa; 404 memset(&sa, 0, sizeof(sa)); 405 sa.sa_handler = SIG_DFL; 406 CHECK_EQ(sigaction(signo, &sa, nullptr), 0); 407 408 ResetStdio(); 409 raise(signo); 410 } 411 } 412} 413#endif // defined(_WIN32) 414#endif // NODE_USE_V8_WASM_TRAP_HANDLER 415 416#ifdef __POSIX__ 417void RegisterSignalHandler(int signal, 418 sigaction_cb handler, 419 bool reset_handler) { 420 CHECK_NOT_NULL(handler); 421#if NODE_USE_V8_WASM_TRAP_HANDLER 422 if (signal == SIGSEGV) { 423 CHECK(previous_sigsegv_action.is_lock_free()); 424 CHECK(!reset_handler); 425 previous_sigsegv_action.store(handler); 426 return; 427 } 428// TODO(align behavior between macos and other in next major version) 429#if defined(__APPLE__) 430 if (signal == SIGBUS) { 431 CHECK(previous_sigbus_action.is_lock_free()); 432 CHECK(!reset_handler); 433 previous_sigbus_action.store(handler); 434 return; 435 } 436#endif // __APPLE__ 437#endif // NODE_USE_V8_WASM_TRAP_HANDLER 438 struct sigaction sa; 439 memset(&sa, 0, sizeof(sa)); 440 sa.sa_sigaction = handler; 441 sa.sa_flags = reset_handler ? SA_RESETHAND : 0; 442 sigfillset(&sa.sa_mask); 443 CHECK_EQ(sigaction(signal, &sa, nullptr), 0); 444} 445#endif // __POSIX__ 446 447#ifdef __POSIX__ 448static struct { 449 int flags; 450 bool isatty; 451 struct stat stat; 452 struct termios termios; 453} stdio[1 + STDERR_FILENO]; 454#endif // __POSIX__ 455 456void ResetSignalHandlers() { 457#ifdef __POSIX__ 458 // Restore signal dispositions, the parent process may have changed them. 459 struct sigaction act; 460 memset(&act, 0, sizeof(act)); 461 462 // The hard-coded upper limit is because NSIG is not very reliable; on Linux, 463 // it evaluates to 32, 34 or 64, depending on whether RT signals are enabled. 464 // Counting up to SIGRTMIN doesn't work for the same reason. 465 for (unsigned nr = 1; nr < kMaxSignal; nr += 1) { 466 if (nr == SIGKILL || nr == SIGSTOP) 467 continue; 468 act.sa_handler = (nr == SIGPIPE || nr == SIGXFSZ) ? SIG_IGN : SIG_DFL; 469 if (act.sa_handler == SIG_DFL) { 470 // The only bad handler value we can inhert from before exec is SIG_IGN 471 // (any actual function pointer is reset to SIG_DFL during exec). 472 // If that's the case, we want to reset it back to SIG_DFL. 473 // However, it's also possible that an embeder (or an LD_PRELOAD-ed 474 // library) has set up own signal handler for own purposes 475 // (e.g. profiling). If that's the case, we want to keep it intact. 476 struct sigaction old; 477 CHECK_EQ(0, sigaction(nr, nullptr, &old)); 478 if ((old.sa_flags & SA_SIGINFO) || old.sa_handler != SIG_IGN) continue; 479 } 480 CHECK_EQ(0, sigaction(nr, &act, nullptr)); 481 } 482#endif // __POSIX__ 483} 484 485static std::atomic<uint32_t> init_process_flags = 0; 486 487static void PlatformInit(ProcessInitializationFlags::Flags flags) { 488 // init_process_flags is accessed in ResetStdio(), 489 // which can be called from signal handlers. 490 CHECK(init_process_flags.is_lock_free()); 491 init_process_flags.store(flags); 492 493 if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) { 494 atexit(ResetStdio); 495 } 496 497#ifdef __POSIX__ 498 if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) { 499 // Disable stdio buffering, it interacts poorly with printf() 500 // calls elsewhere in the program (e.g., any logging from V8.) 501 setvbuf(stdout, nullptr, _IONBF, 0); 502 setvbuf(stderr, nullptr, _IONBF, 0); 503 504 // Make sure file descriptors 0-2 are valid before we start logging 505 // anything. 506 for (auto& s : stdio) { 507 const int fd = &s - stdio; 508 if (fstat(fd, &s.stat) == 0) continue; 509 510 // Anything but EBADF means something is seriously wrong. We don't 511 // have to special-case EINTR, fstat() is not interruptible. 512 if (errno != EBADF) ABORT(); 513 514 // If EBADF (file descriptor doesn't exist), open /dev/null and duplicate 515 // its file descriptor to the invalid file descriptor. Make sure *that* 516 // file descriptor is valid. POSIX doesn't guarantee the next file 517 // descriptor open(2) gives us is the lowest available number anymore in 518 // POSIX.1-2017, which is why dup2(2) is needed. 519 int null_fd; 520 521 do { 522 null_fd = open("/dev/null", O_RDWR); 523 } while (null_fd < 0 && errno == EINTR); 524 525 if (null_fd != fd) { 526 int err; 527 528 do { 529 err = dup2(null_fd, fd); 530 } while (err < 0 && errno == EINTR); 531 CHECK_EQ(err, 0); 532 } 533 534 if (fstat(fd, &s.stat) < 0) ABORT(); 535 } 536 } 537 538 if (!(flags & ProcessInitializationFlags::kNoDefaultSignalHandling)) { 539#if HAVE_INSPECTOR 540 sigset_t sigmask; 541 sigemptyset(&sigmask); 542 sigaddset(&sigmask, SIGUSR1); 543 const int err = pthread_sigmask(SIG_SETMASK, &sigmask, nullptr); 544 CHECK_EQ(err, 0); 545#endif // HAVE_INSPECTOR 546 547 ResetSignalHandlers(); 548 } 549 550 if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) { 551 // Record the state of the stdio file descriptors so we can restore it 552 // on exit. Needs to happen before installing signal handlers because 553 // they make use of that information. 554 for (auto& s : stdio) { 555 const int fd = &s - stdio; 556 int err; 557 558 do { 559 s.flags = fcntl(fd, F_GETFL); 560 } while (s.flags == -1 && errno == EINTR); // NOLINT 561 CHECK_NE(s.flags, -1); 562 563 if (uv_guess_handle(fd) != UV_TTY) continue; 564 s.isatty = true; 565 566 do { 567 err = tcgetattr(fd, &s.termios); 568 } while (err == -1 && errno == EINTR); // NOLINT 569 CHECK_EQ(err, 0); 570 } 571 } 572 573 if (!(flags & ProcessInitializationFlags::kNoDefaultSignalHandling)) { 574 RegisterSignalHandler(SIGINT, SignalExit, true); 575 RegisterSignalHandler(SIGTERM, SignalExit, true); 576 577#if NODE_USE_V8_WASM_TRAP_HANDLER 578#if defined(_WIN32) 579 { 580 constexpr ULONG first = TRUE; 581 per_process::old_vectored_exception_handler = 582 AddVectoredExceptionHandler(first, TrapWebAssemblyOrContinue); 583 } 584#else 585 // Tell V8 to disable emitting WebAssembly 586 // memory bounds checks. This means that we have 587 // to catch the SIGSEGV/SIGBUS in TrapWebAssemblyOrContinue 588 // and pass the signal context to V8. 589 { 590 struct sigaction sa; 591 memset(&sa, 0, sizeof(sa)); 592 sa.sa_sigaction = TrapWebAssemblyOrContinue; 593 sa.sa_flags = SA_SIGINFO; 594 CHECK_EQ(sigaction(SIGSEGV, &sa, nullptr), 0); 595// TODO(align behavior between macos and other in next major version) 596#if defined(__APPLE__) 597 CHECK_EQ(sigaction(SIGBUS, &sa, nullptr), 0); 598#endif 599 } 600#endif // defined(_WIN32) 601 V8::EnableWebAssemblyTrapHandler(false); 602#endif // NODE_USE_V8_WASM_TRAP_HANDLER 603 } 604 605 if (!(flags & ProcessInitializationFlags::kNoAdjustResourceLimits)) { 606 // Raise the open file descriptor limit. 607 struct rlimit lim; 608 if (getrlimit(RLIMIT_NOFILE, &lim) == 0 && lim.rlim_cur != lim.rlim_max) { 609 // Do a binary search for the limit. 610 rlim_t min = lim.rlim_cur; 611 rlim_t max = 1 << 20; 612 // But if there's a defined upper bound, don't search, just set it. 613 if (lim.rlim_max != RLIM_INFINITY) { 614 min = lim.rlim_max; 615 max = lim.rlim_max; 616 } 617 do { 618 lim.rlim_cur = min + (max - min) / 2; 619 if (setrlimit(RLIMIT_NOFILE, &lim)) { 620 max = lim.rlim_cur; 621 } else { 622 min = lim.rlim_cur; 623 } 624 } while (min + 1 < max); 625 } 626 } 627#endif // __POSIX__ 628#ifdef _WIN32 629 if (!(flags & ProcessInitializationFlags::kNoStdioInitialization)) { 630 for (int fd = 0; fd <= 2; ++fd) { 631 auto handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd)); 632 if (handle == INVALID_HANDLE_VALUE || 633 GetFileType(handle) == FILE_TYPE_UNKNOWN) { 634 // Ignore _close result. If it fails or not depends on used Windows 635 // version. We will just check _open result. 636 _close(fd); 637 if (fd != _open("nul", _O_RDWR)) ABORT(); 638 } 639 } 640 } 641#endif // _WIN32 642} 643 644// Safe to call more than once and from signal handlers. 645void ResetStdio() { 646 if (init_process_flags.load() & 647 ProcessInitializationFlags::kNoStdioInitialization) { 648 return; 649 } 650 651 uv_tty_reset_mode(); 652#ifdef __POSIX__ 653 for (auto& s : stdio) { 654 const int fd = &s - stdio; 655 656 struct stat tmp; 657 if (-1 == fstat(fd, &tmp)) { 658 CHECK_EQ(errno, EBADF); // Program closed file descriptor. 659 continue; 660 } 661 662 bool is_same_file = 663 (s.stat.st_dev == tmp.st_dev && s.stat.st_ino == tmp.st_ino); 664 if (!is_same_file) continue; // Program reopened file descriptor. 665 666 int flags; 667 do 668 flags = fcntl(fd, F_GETFL); 669 while (flags == -1 && errno == EINTR); // NOLINT 670 CHECK_NE(flags, -1); 671 672 // Restore the O_NONBLOCK flag if it changed. 673 if (O_NONBLOCK & (flags ^ s.flags)) { 674 flags &= ~O_NONBLOCK; 675 flags |= s.flags & O_NONBLOCK; 676 677 int err; 678 do 679 err = fcntl(fd, F_SETFL, flags); 680 while (err == -1 && errno == EINTR); // NOLINT 681 CHECK_NE(err, -1); 682 } 683 684 if (s.isatty) { 685 sigset_t sa; 686 int err; 687 688 // We might be a background job that doesn't own the TTY so block SIGTTOU 689 // before making the tcsetattr() call, otherwise that signal suspends us. 690 sigemptyset(&sa); 691 sigaddset(&sa, SIGTTOU); 692 693 CHECK_EQ(0, pthread_sigmask(SIG_BLOCK, &sa, nullptr)); 694 do 695 err = tcsetattr(fd, TCSANOW, &s.termios); 696 while (err == -1 && errno == EINTR); // NOLINT 697 CHECK_EQ(0, pthread_sigmask(SIG_UNBLOCK, &sa, nullptr)); 698 699 // Normally we expect err == 0. But if macOS App Sandbox is enabled, 700 // tcsetattr will fail with err == -1 and errno == EPERM. 701 CHECK_IMPLIES(err != 0, err == -1 && errno == EPERM); 702 } 703 } 704#endif // __POSIX__ 705} 706 707 708int ProcessGlobalArgs(std::vector<std::string>* args, 709 std::vector<std::string>* exec_args, 710 std::vector<std::string>* errors, 711 OptionEnvvarSettings settings) { 712 // Parse a few arguments which are specific to Node. 713 std::vector<std::string> v8_args; 714 715 Mutex::ScopedLock lock(per_process::cli_options_mutex); 716 options_parser::Parse( 717 args, 718 exec_args, 719 &v8_args, 720 per_process::cli_options.get(), 721 settings, 722 errors); 723 724 if (!errors->empty()) return 9; 725 726 std::string revert_error; 727 for (const std::string& cve : per_process::cli_options->security_reverts) { 728 Revert(cve.c_str(), &revert_error); 729 if (!revert_error.empty()) { 730 errors->emplace_back(std::move(revert_error)); 731 return 12; 732 } 733 } 734 735 if (per_process::cli_options->disable_proto != "delete" && 736 per_process::cli_options->disable_proto != "throw" && 737 per_process::cli_options->disable_proto != "") { 738 errors->emplace_back("invalid mode passed to --disable-proto"); 739 return 12; 740 } 741 742 // TODO(aduh95): remove this when the harmony-import-assertions flag 743 // is removed in V8. 744 if (std::find(v8_args.begin(), v8_args.end(), 745 "--no-harmony-import-assertions") == v8_args.end()) { 746 v8_args.emplace_back("--harmony-import-assertions"); 747 } 748 749 auto env_opts = per_process::cli_options->per_isolate->per_env; 750 if (std::find(v8_args.begin(), v8_args.end(), 751 "--abort-on-uncaught-exception") != v8_args.end() || 752 std::find(v8_args.begin(), v8_args.end(), 753 "--abort_on_uncaught_exception") != v8_args.end()) { 754 env_opts->abort_on_uncaught_exception = true; 755 } 756 757#ifdef __POSIX__ 758 // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the 759 // performance penalty of frequent EINTR wakeups when the profiler is running. 760 // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users. 761 if (std::find(v8_args.begin(), v8_args.end(), "--prof") != v8_args.end()) { 762 uv_loop_configure(uv_default_loop(), UV_LOOP_BLOCK_SIGNAL, SIGPROF); 763 } 764#endif 765 766 std::vector<char*> v8_args_as_char_ptr(v8_args.size()); 767 if (v8_args.size() > 0) { 768 for (size_t i = 0; i < v8_args.size(); ++i) 769 v8_args_as_char_ptr[i] = v8_args[i].data(); 770 int argc = v8_args.size(); 771 V8::SetFlagsFromCommandLine(&argc, v8_args_as_char_ptr.data(), true); 772 v8_args_as_char_ptr.resize(argc); 773 } 774 775 // Anything that's still in v8_argv is not a V8 or a node option. 776 for (size_t i = 1; i < v8_args_as_char_ptr.size(); i++) 777 errors->push_back("bad option: " + std::string(v8_args_as_char_ptr[i])); 778 779 if (v8_args_as_char_ptr.size() > 1) return 9; 780 781 return 0; 782} 783 784static std::atomic_bool init_called{false}; 785 786// TODO(addaleax): Turn this into a wrapper around InitializeOncePerProcess() 787// (with the corresponding additional flags set), then eventually remove this. 788int InitializeNodeWithArgs(std::vector<std::string>* argv, 789 std::vector<std::string>* exec_argv, 790 std::vector<std::string>* errors) { 791 return InitializeNodeWithArgs(argv, exec_argv, errors, 792 ProcessFlags::kNoFlags); 793} 794 795int InitializeNodeWithArgs(std::vector<std::string>* argv, 796 std::vector<std::string>* exec_argv, 797 std::vector<std::string>* errors, 798 ProcessInitializationFlags::Flags flags) { 799 // Make sure InitializeNodeWithArgs() is called only once. 800 CHECK(!init_called.exchange(true)); 801 802 // Initialize node_start_time to get relative uptime. 803 per_process::node_start_time = uv_hrtime(); 804 805 // Register built-in bindings 806 binding::RegisterBuiltinBindings(); 807 808 // Make inherited handles noninheritable. 809 if (!(flags & ProcessInitializationFlags::kEnableStdioInheritance) && 810 !(flags & ProcessInitializationFlags::kNoStdioInitialization)) { 811 uv_disable_stdio_inheritance(); 812 } 813 814 // Cache the original command line to be 815 // used in diagnostic reports. 816 per_process::cli_options->cmdline = *argv; 817 818#if defined(NODE_V8_OPTIONS) 819 // Should come before the call to V8::SetFlagsFromCommandLine() 820 // so the user can disable a flag --foo at run-time by passing 821 // --no_foo from the command line. 822 V8::SetFlagsFromString(NODE_V8_OPTIONS, sizeof(NODE_V8_OPTIONS) - 1); 823#endif 824 825 HandleEnvOptions(per_process::cli_options->per_isolate->per_env); 826 827#if !defined(NODE_WITHOUT_NODE_OPTIONS) 828 if (!(flags & ProcessInitializationFlags::kDisableNodeOptionsEnv)) { 829 std::string node_options; 830 831 if (credentials::SafeGetenv("NODE_OPTIONS", &node_options)) { 832 std::vector<std::string> env_argv = 833 ParseNodeOptionsEnvVar(node_options, errors); 834 835 if (!errors->empty()) return 9; 836 837 // [0] is expected to be the program name, fill it in from the real argv. 838 env_argv.insert(env_argv.begin(), argv->at(0)); 839 840 const int exit_code = ProcessGlobalArgs(&env_argv, 841 nullptr, 842 errors, 843 kAllowedInEnvvar); 844 if (exit_code != 0) return exit_code; 845 } 846 } 847#endif 848 849 if (!(flags & ProcessInitializationFlags::kDisableCLIOptions)) { 850 const int exit_code = ProcessGlobalArgs(argv, 851 exec_argv, 852 errors, 853 kDisallowedInEnvvar); 854 if (exit_code != 0) return exit_code; 855 } 856 857 // Set the process.title immediately after processing argv if --title is set. 858 if (!per_process::cli_options->title.empty()) 859 uv_set_process_title(per_process::cli_options->title.c_str()); 860 861#if defined(NODE_HAVE_I18N_SUPPORT) 862 if (!(flags & ProcessInitializationFlags::kNoICU)) { 863 // If the parameter isn't given, use the env variable. 864 if (per_process::cli_options->icu_data_dir.empty()) 865 credentials::SafeGetenv("NODE_ICU_DATA", 866 &per_process::cli_options->icu_data_dir); 867 868#ifdef NODE_ICU_DEFAULT_DATA_DIR 869 // If neither the CLI option nor the environment variable was specified, 870 // fall back to the configured default 871 if (per_process::cli_options->icu_data_dir.empty()) { 872 // Check whether the NODE_ICU_DEFAULT_DATA_DIR contains the right data 873 // file and can be read. 874 static const char full_path[] = 875 NODE_ICU_DEFAULT_DATA_DIR "/" U_ICUDATA_NAME ".dat"; 876 877 FILE* f = fopen(full_path, "rb"); 878 879 if (f != nullptr) { 880 fclose(f); 881 per_process::cli_options->icu_data_dir = NODE_ICU_DEFAULT_DATA_DIR; 882 } 883 } 884#endif // NODE_ICU_DEFAULT_DATA_DIR 885 886 // Initialize ICU. 887 // If icu_data_dir is empty here, it will load the 'minimal' data. 888 if (!i18n::InitializeICUDirectory(per_process::cli_options->icu_data_dir)) { 889 errors->push_back("could not initialize ICU " 890 "(check NODE_ICU_DATA or --icu-data-dir parameters)\n"); 891 return 9; 892 } 893 per_process::metadata.versions.InitializeIntlVersions(); 894 } 895 896# ifndef __POSIX__ 897 std::string tz; 898 if (credentials::SafeGetenv("TZ", &tz) && !tz.empty()) { 899 i18n::SetDefaultTimeZone(tz.c_str()); 900 } 901# endif 902 903#endif // defined(NODE_HAVE_I18N_SUPPORT) 904 905 // We should set node_is_initialized here instead of in node::Start, 906 // otherwise embedders using node::Init to initialize everything will not be 907 // able to set it and native addons will not load for them. 908 node_is_initialized = true; 909 return 0; 910} 911 912std::unique_ptr<InitializationResult> InitializeOncePerProcess( 913 const std::vector<std::string>& args, 914 ProcessInitializationFlags::Flags flags) { 915 auto result = std::make_unique<InitializationResultImpl>(); 916 result->args_ = args; 917 918 if (!(flags & ProcessInitializationFlags::kNoParseGlobalDebugVariables)) { 919 // Initialized the enabled list for Debug() calls with system 920 // environment variables. 921 per_process::enabled_debug_list.Parse(); 922 } 923 924 PlatformInit(flags); 925 926 // This needs to run *before* V8::Initialize(). 927 { 928 result->exit_code_ = InitializeNodeWithArgs( 929 &result->args_, &result->exec_args_, &result->errors_, flags); 930 if (result->exit_code() != 0) { 931 result->early_return_ = true; 932 return result; 933 } 934 } 935 936 if (!(flags & ProcessInitializationFlags::kNoUseLargePages) && 937 (per_process::cli_options->use_largepages == "on" || 938 per_process::cli_options->use_largepages == "silent")) { 939 int lp_result = node::MapStaticCodeToLargePages(); 940 if (per_process::cli_options->use_largepages == "on" && lp_result != 0) { 941 result->errors_.emplace_back(node::LargePagesError(lp_result)); 942 } 943 } 944 945 if (!(flags & ProcessInitializationFlags::kNoPrintHelpOrVersionOutput)) { 946 if (per_process::cli_options->print_version) { 947 printf("%s\n", NODE_VERSION); 948 result->exit_code_ = 0; 949 result->early_return_ = true; 950 return result; 951 } 952 953 if (per_process::cli_options->print_bash_completion) { 954 std::string completion = options_parser::GetBashCompletion(); 955 printf("%s\n", completion.c_str()); 956 result->exit_code_ = 0; 957 result->early_return_ = true; 958 return result; 959 } 960 961 if (per_process::cli_options->print_v8_help) { 962 V8::SetFlagsFromString("--help", static_cast<size_t>(6)); 963 result->exit_code_ = 0; 964 result->early_return_ = true; 965 return result; 966 } 967 } 968 969 if (!(flags & ProcessInitializationFlags::kNoInitOpenSSL)) { 970#if HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL) 971 auto GetOpenSSLErrorString = []() -> std::string { 972 std::string ret; 973 ERR_print_errors_cb( 974 [](const char* str, size_t len, void* opaque) { 975 std::string* ret = static_cast<std::string*>(opaque); 976 ret->append(str, len); 977 ret->append("\n"); 978 return 0; 979 }, 980 static_cast<void*>(&ret)); 981 return ret; 982 }; 983 984 // In the case of FIPS builds we should make sure 985 // the random source is properly initialized first. 986#if OPENSSL_VERSION_MAJOR >= 3 987 // Call OPENSSL_init_crypto to initialize OPENSSL_INIT_LOAD_CONFIG to 988 // avoid the default behavior where errors raised during the parsing of the 989 // OpenSSL configuration file are not propagated and cannot be detected. 990 // 991 // If FIPS is configured the OpenSSL configuration file will have an 992 // .include pointing to the fipsmodule.cnf file generated by the openssl 993 // fipsinstall command. If the path to this file is incorrect no error 994 // will be reported. 995 // 996 // For Node.js this will mean that CSPRNG() will be called by V8 as 997 // part of its initialization process, and CSPRNG() will in turn call 998 // call RAND_status which will now always return 0, leading to an endless 999 // loop and the node process will appear to hang/freeze. 1000 1001 // Passing NULL as the config file will allow the default openssl.cnf file 1002 // to be loaded, but the default section in that file will not be used, 1003 // instead only the section that matches the value of conf_section_name 1004 // will be read from the default configuration file. 1005 const char* conf_file = nullptr; 1006 // To allow for using the previous default where the 'openssl_conf' appname 1007 // was used, the command line option 'openssl-shared-config' can be used to 1008 // force the old behavior. 1009 if (per_process::cli_options->openssl_shared_config) { 1010 conf_section_name = "openssl_conf"; 1011 } 1012 // Use OPENSSL_CONF environment variable is set. 1013 std::string env_openssl_conf; 1014 credentials::SafeGetenv("OPENSSL_CONF", &env_openssl_conf); 1015 if (!env_openssl_conf.empty()) { 1016 conf_file = env_openssl_conf.c_str(); 1017 } 1018 // Use --openssl-conf command line option if specified. 1019 if (!per_process::cli_options->openssl_config.empty()) { 1020 conf_file = per_process::cli_options->openssl_config.c_str(); 1021 } 1022 1023 OPENSSL_INIT_SETTINGS* settings = OPENSSL_INIT_new(); 1024 OPENSSL_INIT_set_config_filename(settings, conf_file); 1025 OPENSSL_INIT_set_config_appname(settings, conf_section_name); 1026 OPENSSL_INIT_set_config_file_flags(settings, 1027 CONF_MFLAGS_IGNORE_MISSING_FILE); 1028 1029 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CONFIG, settings); 1030 OPENSSL_INIT_free(settings); 1031 1032 if (ERR_peek_error() != 0) { 1033 // XXX: ERR_GET_REASON does not return something that is 1034 // useful as an exit code at all. 1035 result->exit_code_ = ERR_GET_REASON(ERR_peek_error()); 1036 result->early_return_ = true; 1037 result->errors_.emplace_back("OpenSSL configuration error:\n" + 1038 GetOpenSSLErrorString()); 1039 return result; 1040 } 1041#else // OPENSSL_VERSION_MAJOR < 3 1042 if (FIPS_mode()) { 1043 OPENSSL_init(); 1044 } 1045#endif 1046 if (!crypto::ProcessFipsOptions()) { 1047 // XXX: ERR_GET_REASON does not return something that is 1048 // useful as an exit code at all. 1049 result->exit_code_ = ERR_GET_REASON(ERR_peek_error()); 1050 result->early_return_ = true; 1051 result->errors_.emplace_back( 1052 "OpenSSL error when trying to enable FIPS:\n" + 1053 GetOpenSSLErrorString()); 1054 return result; 1055 } 1056 1057 // Ensure CSPRNG is properly seeded. 1058 CHECK(crypto::CSPRNG(nullptr, 0).is_ok()); 1059 1060 V8::SetEntropySource([](unsigned char* buffer, size_t length) { 1061 // V8 falls back to very weak entropy when this function fails 1062 // and /dev/urandom isn't available. That wouldn't be so bad if 1063 // the entropy was only used for Math.random() but it's also used for 1064 // hash table and address space layout randomization. Better to abort. 1065 CHECK(crypto::CSPRNG(buffer, length).is_ok()); 1066 return true; 1067 }); 1068 1069 { 1070 std::string extra_ca_certs; 1071 if (credentials::SafeGetenv("NODE_EXTRA_CA_CERTS", &extra_ca_certs)) 1072 crypto::UseExtraCaCerts(extra_ca_certs); 1073 } 1074#endif // HAVE_OPENSSL && !defined(OPENSSL_IS_BORINGSSL) 1075 } 1076 1077 if (!(flags & ProcessInitializationFlags::kNoInitializeNodeV8Platform)) { 1078 per_process::v8_platform.Initialize( 1079 static_cast<int>(per_process::cli_options->v8_thread_pool_size)); 1080 result->platform_ = per_process::v8_platform.Platform(); 1081 } 1082 1083 if (!(flags & ProcessInitializationFlags::kNoInitializeV8)) { 1084 V8::Initialize(); 1085 } 1086 1087 performance::performance_v8_start = PERFORMANCE_NOW(); 1088 per_process::v8_initialized = true; 1089 1090 return result; 1091} 1092 1093void TearDownOncePerProcess() { 1094 const uint64_t flags = init_process_flags.load(); 1095 ResetStdio(); 1096 if (!(flags & ProcessInitializationFlags::kNoDefaultSignalHandling)) { 1097 ResetSignalHandlers(); 1098 } 1099 1100 per_process::v8_initialized = false; 1101 if (!(flags & ProcessInitializationFlags::kNoInitializeV8)) { 1102 V8::Dispose(); 1103 } 1104 1105#if NODE_USE_V8_WASM_TRAP_HANDLER && defined(_WIN32) 1106 if (!(flags & ProcessInitializationFlags::kNoDefaultSignalHandling)) { 1107 RemoveVectoredExceptionHandler(per_process::old_vectored_exception_handler); 1108 } 1109#endif 1110 1111 if (!(flags & ProcessInitializationFlags::kNoInitializeNodeV8Platform)) { 1112 V8::DisposePlatform(); 1113 // uv_run cannot be called from the time before the beforeExit callback 1114 // runs until the program exits unless the event loop has any referenced 1115 // handles after beforeExit terminates. This prevents unrefed timers 1116 // that happen to terminate during shutdown from being run unsafely. 1117 // Since uv_run cannot be called, uv_async handles held by the platform 1118 // will never be fully cleaned up. 1119 per_process::v8_platform.Dispose(); 1120 } 1121} 1122 1123InitializationResult::~InitializationResult() {} 1124InitializationResultImpl::~InitializationResultImpl() {} 1125 1126int GenerateAndWriteSnapshotData(const SnapshotData** snapshot_data_ptr, 1127 const InitializationResult* result) { 1128 int exit_code = result->exit_code(); 1129 // nullptr indicates there's no snapshot data. 1130 DCHECK_NULL(*snapshot_data_ptr); 1131 1132 // node:embedded_snapshot_main indicates that we are using the 1133 // embedded snapshot and we are not supposed to clean it up. 1134 if (result->args()[1] == "node:embedded_snapshot_main") { 1135 *snapshot_data_ptr = SnapshotBuilder::GetEmbeddedSnapshotData(); 1136 if (*snapshot_data_ptr == nullptr) { 1137 // The Node.js binary is built without embedded snapshot 1138 fprintf(stderr, 1139 "node:embedded_snapshot_main was specified as snapshot " 1140 "entry point but Node.js was built without embedded " 1141 "snapshot.\n"); 1142 exit_code = 1; 1143 return exit_code; 1144 } 1145 } else { 1146 // Otherwise, load and run the specified main script. 1147 std::unique_ptr<SnapshotData> generated_data = 1148 std::make_unique<SnapshotData>(); 1149 exit_code = node::SnapshotBuilder::Generate( 1150 generated_data.get(), result->args(), result->exec_args()); 1151 if (exit_code == 0) { 1152 *snapshot_data_ptr = generated_data.release(); 1153 } else { 1154 return exit_code; 1155 } 1156 } 1157 1158 // Get the path to write the snapshot blob to. 1159 std::string snapshot_blob_path; 1160 if (!per_process::cli_options->snapshot_blob.empty()) { 1161 snapshot_blob_path = per_process::cli_options->snapshot_blob; 1162 } else { 1163 // Defaults to snapshot.blob in the current working directory. 1164 snapshot_blob_path = std::string("snapshot.blob"); 1165 } 1166 1167 FILE* fp = fopen(snapshot_blob_path.c_str(), "wb"); 1168 if (fp != nullptr) { 1169 (*snapshot_data_ptr)->ToBlob(fp); 1170 fclose(fp); 1171 } else { 1172 fprintf(stderr, 1173 "Cannot open %s for writing a snapshot.\n", 1174 snapshot_blob_path.c_str()); 1175 exit_code = 1; 1176 } 1177 return exit_code; 1178} 1179 1180int LoadSnapshotDataAndRun(const SnapshotData** snapshot_data_ptr, 1181 const InitializationResult* result) { 1182 int exit_code = result->exit_code(); 1183 // nullptr indicates there's no snapshot data. 1184 DCHECK_NULL(*snapshot_data_ptr); 1185 // --snapshot-blob indicates that we are reading a customized snapshot. 1186 if (!per_process::cli_options->snapshot_blob.empty()) { 1187 std::string filename = per_process::cli_options->snapshot_blob; 1188 FILE* fp = fopen(filename.c_str(), "rb"); 1189 if (fp == nullptr) { 1190 fprintf(stderr, "Cannot open %s", filename.c_str()); 1191 exit_code = 1; 1192 return exit_code; 1193 } 1194 std::unique_ptr<SnapshotData> read_data = std::make_unique<SnapshotData>(); 1195 bool ok = SnapshotData::FromBlob(read_data.get(), fp); 1196 fclose(fp); 1197 if (!ok) { 1198 // If we fail to read the customized snapshot, simply exit with 1. 1199 exit_code = 1; 1200 return exit_code; 1201 } 1202 *snapshot_data_ptr = read_data.release(); 1203 } else if (per_process::cli_options->node_snapshot) { 1204 // If --snapshot-blob is not specified, we are reading the embedded 1205 // snapshot, but we will skip it if --no-node-snapshot is specified. 1206 const node::SnapshotData* read_data = 1207 SnapshotBuilder::GetEmbeddedSnapshotData(); 1208 if (read_data != nullptr && read_data->Check()) { 1209 // If we fail to read the embedded snapshot, treat it as if Node.js 1210 // was built without one. 1211 *snapshot_data_ptr = read_data; 1212 } 1213 } 1214 1215 NodeMainInstance main_instance(*snapshot_data_ptr, 1216 uv_default_loop(), 1217 per_process::v8_platform.Platform(), 1218 result->args(), 1219 result->exec_args()); 1220 exit_code = main_instance.Run(); 1221 return exit_code; 1222} 1223 1224int Start(int argc, char** argv) { 1225#ifndef DISABLE_SINGLE_EXECUTABLE_APPLICATION 1226 std::tie(argc, argv) = sea::FixupArgsForSEA(argc, argv); 1227#endif 1228 1229 CHECK_GT(argc, 0); 1230 1231 // Hack around with the argv pointer. Used for process.title = "blah". 1232 argv = uv_setup_args(argc, argv); 1233 1234 std::unique_ptr<InitializationResult> result = 1235 InitializeOncePerProcess(std::vector<std::string>(argv, argv + argc)); 1236 for (const std::string& error : result->errors()) { 1237 FPrintF(stderr, "%s: %s\n", result->args().at(0), error); 1238 } 1239 if (result->early_return()) { 1240 return result->exit_code(); 1241 } 1242 1243 DCHECK_EQ(result->exit_code(), 0); 1244 const SnapshotData* snapshot_data = nullptr; 1245 1246 auto cleanup_process = OnScopeLeave([&]() { 1247 TearDownOncePerProcess(); 1248 1249 if (snapshot_data != nullptr && 1250 snapshot_data->data_ownership == SnapshotData::DataOwnership::kOwned) { 1251 delete snapshot_data; 1252 } 1253 }); 1254 1255 uv_loop_configure(uv_default_loop(), UV_METRICS_IDLE_TIME); 1256 1257 // --build-snapshot indicates that we are in snapshot building mode. 1258 if (per_process::cli_options->build_snapshot) { 1259 if (result->args().size() < 2) { 1260 fprintf(stderr, 1261 "--build-snapshot must be used with an entry point script.\n" 1262 "Usage: node --build-snapshot /path/to/entry.js\n"); 1263 return 9; 1264 } 1265 return GenerateAndWriteSnapshotData(&snapshot_data, result.get()); 1266 } 1267 1268 // Without --build-snapshot, we are in snapshot loading mode. 1269 return LoadSnapshotDataAndRun(&snapshot_data, result.get()); 1270} 1271 1272int Stop(Environment* env) { 1273 return Stop(env, StopFlags::kNoFlags); 1274} 1275 1276int Stop(Environment* env, StopFlags::Flags flags) { 1277 env->ExitEnv(flags); 1278 return 0; 1279} 1280 1281} // namespace node 1282 1283#if !HAVE_INSPECTOR 1284void Initialize() {} 1285 1286NODE_BINDING_CONTEXT_AWARE_INTERNAL(inspector, Initialize) 1287#endif // !HAVE_INSPECTOR 1288