@@ -1280,42 +1280,23 @@ inline void PlatformInit() {
12801280#endif // _WIN32
12811281}
12821282
1283- void ProcessArgv (std::vector<std::string>* args,
1284- std::vector<std::string>* exec_args,
1285- bool is_env) {
1283+ int ProcessGlobalArgs (std::vector<std::string>* args,
1284+ std::vector<std::string>* exec_args,
1285+ std::vector<std::string>* errors,
1286+ bool is_env) {
12861287 // Parse a few arguments which are specific to Node.
12871288 std::vector<std::string> v8_args;
1288- std::vector<std::string> errors{};
12891289
1290- {
1291- // TODO(addaleax): The mutex here should ideally be held during the
1292- // entire function, but that doesn't play well with the exit() calls below.
1293- Mutex::ScopedLock lock (per_process::cli_options_mutex);
1294- options_parser::PerProcessOptionsParser::instance.Parse (
1295- args,
1296- exec_args,
1297- &v8_args,
1298- per_process::cli_options.get (),
1299- is_env ? kAllowedInEnvironment : kDisallowedInEnvironment ,
1300- &errors);
1301- }
1302-
1303- if (!errors.empty ()) {
1304- for (auto const & error : errors) {
1305- fprintf (stderr, " %s: %s\n " , args->at (0 ).c_str (), error.c_str ());
1306- }
1307- exit (9 );
1308- }
1290+ Mutex::ScopedLock lock (per_process::cli_options_mutex);
1291+ options_parser::PerProcessOptionsParser::instance.Parse (
1292+ args,
1293+ exec_args,
1294+ &v8_args,
1295+ per_process::cli_options.get (),
1296+ is_env ? kAllowedInEnvironment : kDisallowedInEnvironment ,
1297+ errors);
13091298
1310- if (per_process::cli_options->print_version ) {
1311- printf (" %s\n " , NODE_VERSION);
1312- exit (0 );
1313- }
1314-
1315- if (per_process::cli_options->print_v8_help ) {
1316- V8::SetFlagsFromString (" --help" , 6 );
1317- exit (0 );
1318- }
1299+ if (!errors->empty ()) return 9 ;
13191300
13201301 for (const std::string& cve : per_process::cli_options->security_reverts )
13211302 Revert (cve.c_str ());
@@ -1355,19 +1336,17 @@ void ProcessArgv(std::vector<std::string>* args,
13551336 }
13561337
13571338 // Anything that's still in v8_argv is not a V8 or a node option.
1358- for (size_t i = 1 ; i < v8_args_as_char_ptr.size (); i++) {
1359- fprintf (stderr, " %s: bad option: %s\n " ,
1360- args->at (0 ).c_str (), v8_args_as_char_ptr[i]);
1361- }
1339+ for (size_t i = 1 ; i < v8_args_as_char_ptr.size (); i++)
1340+ errors->push_back (" bad option: " + std::string (v8_args_as_char_ptr[i]));
13621341
1363- if (v8_args_as_char_ptr.size () > 1 ) {
1364- exit (9 );
1365- }
1366- }
1342+ if (v8_args_as_char_ptr.size () > 1 ) return 9 ;
13671343
1344+ return 0 ;
1345+ }
13681346
1369- void Init (std::vector<std::string>* argv,
1370- std::vector<std::string>* exec_argv) {
1347+ int Init (std::vector<std::string>* argv,
1348+ std::vector<std::string>* exec_argv,
1349+ std::vector<std::string>* errors) {
13711350 // Initialize prog_start_time to get relative uptime.
13721351 per_process::prog_start_time = static_cast <double >(uv_now (uv_default_loop ()));
13731352
@@ -1428,11 +1407,13 @@ void Init(std::vector<std::string>* argv,
14281407 std::vector<std::string> env_argv = SplitString (" x " + node_options, ' ' );
14291408 env_argv[0 ] = argv->at (0 );
14301409
1431- ProcessArgv (&env_argv, nullptr , true );
1410+ const int exit_code = ProcessGlobalArgs (&env_argv, nullptr , errors, true );
1411+ if (exit_code != 0 ) return exit_code;
14321412 }
14331413#endif
14341414
1435- ProcessArgv (argv, exec_argv, false );
1415+ const int exit_code = ProcessGlobalArgs (argv, exec_argv, errors, false );
1416+ if (exit_code != 0 ) return exit_code;
14361417
14371418 // Set the process.title immediately after processing argv if --title is set.
14381419 if (!per_process::cli_options->title .empty ())
@@ -1446,11 +1427,9 @@ void Init(std::vector<std::string>* argv,
14461427 // Initialize ICU.
14471428 // If icu_data_dir is empty here, it will load the 'minimal' data.
14481429 if (!i18n::InitializeICUDirectory (per_process::cli_options->icu_data_dir )) {
1449- fprintf (stderr,
1450- " %s: could not initialize ICU "
1451- " (check NODE_ICU_DATA or --icu-data-dir parameters)\n " ,
1452- argv->at (0 ).c_str ());
1453- exit (9 );
1430+ errors->push_back (" could not initialize ICU "
1431+ " (check NODE_ICU_DATA or --icu-data-dir parameters)\n " );
1432+ return 9 ;
14541433 }
14551434 per_process::metadata.versions .InitializeIntlVersions ();
14561435#endif
@@ -1459,6 +1438,7 @@ void Init(std::vector<std::string>* argv,
14591438 // otherwise embedders using node::Init to initialize everything will not be
14601439 // able to set it and native modules will not load for them.
14611440 node_is_initialized = true ;
1441+ return 0 ;
14621442}
14631443
14641444// TODO(addaleax): Deprecate and eventually remove this.
@@ -1468,8 +1448,25 @@ void Init(int* argc,
14681448 const char *** exec_argv) {
14691449 std::vector<std::string> argv_ (argv, argv + *argc); // NOLINT
14701450 std::vector<std::string> exec_argv_;
1451+ std::vector<std::string> errors;
1452+
1453+ // This (approximately) duplicates some logic that has been moved to
1454+ // node::Start(), with the difference that here we explicitly call `exit()`.
1455+ int exit_code = Init (&argv_, &exec_argv_, &errors);
14711456
1472- Init (&argv_, &exec_argv_);
1457+ for (const std::string& error : errors)
1458+ fprintf (stderr, " %s: %s\n " , argv_.at (0 ).c_str (), error.c_str ());
1459+ if (exit_code != 0 ) exit (exit_code);
1460+
1461+ if (per_process::cli_options->print_version ) {
1462+ printf (" %s\n " , NODE_VERSION);
1463+ exit (0 );
1464+ }
1465+
1466+ if (per_process::cli_options->print_v8_help ) {
1467+ V8::SetFlagsFromString (" --help" , 6 ); // Doesn't return.
1468+ UNREACHABLE ();
1469+ }
14731470
14741471 *argc = argv_.size ();
14751472 *exec_argc = exec_argv_.size ();
@@ -1786,6 +1783,16 @@ inline int Start(uv_loop_t* event_loop,
17861783 if (isolate == nullptr )
17871784 return 12 ; // Signal internal error.
17881785
1786+ if (per_process::cli_options->print_version ) {
1787+ printf (" %s\n " , NODE_VERSION);
1788+ return 0 ;
1789+ }
1790+
1791+ if (per_process::cli_options->print_v8_help ) {
1792+ V8::SetFlagsFromString (" --help" , 6 ); // Doesn't return.
1793+ UNREACHABLE ();
1794+ }
1795+
17891796 {
17901797 Mutex::ScopedLock scoped_lock (per_process::main_isolate_mutex);
17911798 CHECK_NULL (per_process::main_isolate);
@@ -1845,8 +1852,14 @@ int Start(int argc, char** argv) {
18451852
18461853 std::vector<std::string> args (argv, argv + argc);
18471854 std::vector<std::string> exec_args;
1855+ std::vector<std::string> errors;
18481856 // This needs to run *before* V8::Initialize().
1849- Init (&args, &exec_args);
1857+ {
1858+ const int exit_code = Init (&args, &exec_args, &errors);
1859+ for (const std::string& error : errors)
1860+ fprintf (stderr, " %s: %s\n " , args.at (0 ).c_str (), error.c_str ());
1861+ if (exit_code != 0 ) return exit_code;
1862+ }
18501863
18511864#if HAVE_OPENSSL
18521865 {
0 commit comments