Skip to content

Commit b52078f

Browse files
committed
src: clean up node::Init() wrt embedder scenarios
This makes the STL variant of `node::Init()` a bit more suitable for inclusion in a proper embedder API, as errors or other output are reported to the caller rather than directly being printed, and the process is not exited directly either.
1 parent 8d893f2 commit b52078f

File tree

1 file changed

+64
-51
lines changed

1 file changed

+64
-51
lines changed

src/node.cc

Lines changed: 64 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)