Skip to content

Commit 299aefd

Browse files
addaleaxBridgeAR
authored andcommitted
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. PR-URL: #25370 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
1 parent dca6741 commit 299aefd

File tree

1 file changed

+64
-51
lines changed

1 file changed

+64
-51
lines changed

src/node.cc

+64-51
Original file line numberDiff line numberDiff line change
@@ -1151,42 +1151,23 @@ inline void PlatformInit() {
11511151
#endif // _WIN32
11521152
}
11531153

1154-
void ProcessArgv(std::vector<std::string>* args,
1155-
std::vector<std::string>* exec_args,
1156-
bool is_env) {
1154+
int ProcessGlobalArgs(std::vector<std::string>* args,
1155+
std::vector<std::string>* exec_args,
1156+
std::vector<std::string>* errors,
1157+
bool is_env) {
11571158
// Parse a few arguments which are specific to Node.
11581159
std::vector<std::string> v8_args;
1159-
std::vector<std::string> errors{};
11601160

1161-
{
1162-
// TODO(addaleax): The mutex here should ideally be held during the
1163-
// entire function, but that doesn't play well with the exit() calls below.
1164-
Mutex::ScopedLock lock(per_process::cli_options_mutex);
1165-
options_parser::PerProcessOptionsParser::instance.Parse(
1166-
args,
1167-
exec_args,
1168-
&v8_args,
1169-
per_process::cli_options.get(),
1170-
is_env ? kAllowedInEnvironment : kDisallowedInEnvironment,
1171-
&errors);
1172-
}
1173-
1174-
if (!errors.empty()) {
1175-
for (auto const& error : errors) {
1176-
fprintf(stderr, "%s: %s\n", args->at(0).c_str(), error.c_str());
1177-
}
1178-
exit(9);
1179-
}
1161+
Mutex::ScopedLock lock(per_process::cli_options_mutex);
1162+
options_parser::PerProcessOptionsParser::instance.Parse(
1163+
args,
1164+
exec_args,
1165+
&v8_args,
1166+
per_process::cli_options.get(),
1167+
is_env ? kAllowedInEnvironment : kDisallowedInEnvironment,
1168+
errors);
11801169

1181-
if (per_process::cli_options->print_version) {
1182-
printf("%s\n", NODE_VERSION);
1183-
exit(0);
1184-
}
1185-
1186-
if (per_process::cli_options->print_v8_help) {
1187-
V8::SetFlagsFromString("--help", 6);
1188-
exit(0);
1189-
}
1170+
if (!errors->empty()) return 9;
11901171

11911172
for (const std::string& cve : per_process::cli_options->security_reverts)
11921173
Revert(cve.c_str());
@@ -1226,19 +1207,17 @@ void ProcessArgv(std::vector<std::string>* args,
12261207
}
12271208

12281209
// Anything that's still in v8_argv is not a V8 or a node option.
1229-
for (size_t i = 1; i < v8_args_as_char_ptr.size(); i++) {
1230-
fprintf(stderr, "%s: bad option: %s\n",
1231-
args->at(0).c_str(), v8_args_as_char_ptr[i]);
1232-
}
1210+
for (size_t i = 1; i < v8_args_as_char_ptr.size(); i++)
1211+
errors->push_back("bad option: " + std::string(v8_args_as_char_ptr[i]));
12331212

1234-
if (v8_args_as_char_ptr.size() > 1) {
1235-
exit(9);
1236-
}
1237-
}
1213+
if (v8_args_as_char_ptr.size() > 1) return 9;
12381214

1215+
return 0;
1216+
}
12391217

1240-
void Init(std::vector<std::string>* argv,
1241-
std::vector<std::string>* exec_argv) {
1218+
int Init(std::vector<std::string>* argv,
1219+
std::vector<std::string>* exec_argv,
1220+
std::vector<std::string>* errors) {
12421221
// Initialize prog_start_time to get relative uptime.
12431222
per_process::prog_start_time = static_cast<double>(uv_now(uv_default_loop()));
12441223

@@ -1299,11 +1278,13 @@ void Init(std::vector<std::string>* argv,
12991278
std::vector<std::string> env_argv = SplitString("x " + node_options, ' ');
13001279
env_argv[0] = argv->at(0);
13011280

1302-
ProcessArgv(&env_argv, nullptr, true);
1281+
const int exit_code = ProcessGlobalArgs(&env_argv, nullptr, errors, true);
1282+
if (exit_code != 0) return exit_code;
13031283
}
13041284
#endif
13051285

1306-
ProcessArgv(argv, exec_argv, false);
1286+
const int exit_code = ProcessGlobalArgs(argv, exec_argv, errors, false);
1287+
if (exit_code != 0) return exit_code;
13071288

13081289
// Set the process.title immediately after processing argv if --title is set.
13091290
if (!per_process::cli_options->title.empty())
@@ -1317,11 +1298,9 @@ void Init(std::vector<std::string>* argv,
13171298
// Initialize ICU.
13181299
// If icu_data_dir is empty here, it will load the 'minimal' data.
13191300
if (!i18n::InitializeICUDirectory(per_process::cli_options->icu_data_dir)) {
1320-
fprintf(stderr,
1321-
"%s: could not initialize ICU "
1322-
"(check NODE_ICU_DATA or --icu-data-dir parameters)\n",
1323-
argv->at(0).c_str());
1324-
exit(9);
1301+
errors->push_back("could not initialize ICU "
1302+
"(check NODE_ICU_DATA or --icu-data-dir parameters)\n");
1303+
return 9;
13251304
}
13261305
per_process::metadata.versions.InitializeIntlVersions();
13271306
#endif
@@ -1330,6 +1309,7 @@ void Init(std::vector<std::string>* argv,
13301309
// otherwise embedders using node::Init to initialize everything will not be
13311310
// able to set it and native modules will not load for them.
13321311
node_is_initialized = true;
1312+
return 0;
13331313
}
13341314

13351315
// TODO(addaleax): Deprecate and eventually remove this.
@@ -1339,8 +1319,25 @@ void Init(int* argc,
13391319
const char*** exec_argv) {
13401320
std::vector<std::string> argv_(argv, argv + *argc); // NOLINT
13411321
std::vector<std::string> exec_argv_;
1322+
std::vector<std::string> errors;
1323+
1324+
// This (approximately) duplicates some logic that has been moved to
1325+
// node::Start(), with the difference that here we explicitly call `exit()`.
1326+
int exit_code = Init(&argv_, &exec_argv_, &errors);
13421327

1343-
Init(&argv_, &exec_argv_);
1328+
for (const std::string& error : errors)
1329+
fprintf(stderr, "%s: %s\n", argv_.at(0).c_str(), error.c_str());
1330+
if (exit_code != 0) exit(exit_code);
1331+
1332+
if (per_process::cli_options->print_version) {
1333+
printf("%s\n", NODE_VERSION);
1334+
exit(0);
1335+
}
1336+
1337+
if (per_process::cli_options->print_v8_help) {
1338+
V8::SetFlagsFromString("--help", 6); // Doesn't return.
1339+
UNREACHABLE();
1340+
}
13441341

13451342
*argc = argv_.size();
13461343
*exec_argc = exec_argv_.size();
@@ -1657,6 +1654,16 @@ inline int Start(uv_loop_t* event_loop,
16571654
if (isolate == nullptr)
16581655
return 12; // Signal internal error.
16591656

1657+
if (per_process::cli_options->print_version) {
1658+
printf("%s\n", NODE_VERSION);
1659+
return 0;
1660+
}
1661+
1662+
if (per_process::cli_options->print_v8_help) {
1663+
V8::SetFlagsFromString("--help", 6); // Doesn't return.
1664+
UNREACHABLE();
1665+
}
1666+
16601667
{
16611668
Mutex::ScopedLock scoped_lock(per_process::main_isolate_mutex);
16621669
CHECK_NULL(per_process::main_isolate);
@@ -1716,8 +1723,14 @@ int Start(int argc, char** argv) {
17161723

17171724
std::vector<std::string> args(argv, argv + argc);
17181725
std::vector<std::string> exec_args;
1726+
std::vector<std::string> errors;
17191727
// This needs to run *before* V8::Initialize().
1720-
Init(&args, &exec_args);
1728+
{
1729+
const int exit_code = Init(&args, &exec_args, &errors);
1730+
for (const std::string& error : errors)
1731+
fprintf(stderr, "%s: %s\n", args.at(0).c_str(), error.c_str());
1732+
if (exit_code != 0) return exit_code;
1733+
}
17211734

17221735
#if HAVE_OPENSSL
17231736
{

0 commit comments

Comments
 (0)