@@ -3626,6 +3626,9 @@ static void PrintHelp() {
3626
3626
#endif
3627
3627
#endif
3628
3628
" NODE_NO_WARNINGS set to 1 to silence process warnings\n "
3629
+ #if !defined(NODE_WITHOUT_NODE_OPTIONS)
3630
+ " NODE_OPTIONS set CLI options in the environment\n "
3631
+ #endif
3629
3632
#ifdef _WIN32
3630
3633
" NODE_PATH ';'-separated list of directories\n "
3631
3634
#else
@@ -3642,6 +3645,51 @@ static void PrintHelp() {
3642
3645
}
3643
3646
3644
3647
3648
+ static void CheckIfAllowedInEnv (const char * exe, bool is_env,
3649
+ const char * arg) {
3650
+ if (!is_env)
3651
+ return ;
3652
+
3653
+ // Find the arg prefix when its --some_arg=val
3654
+ const char * eq = strchr (arg, ' =' );
3655
+ size_t arglen = eq ? eq - arg : strlen (arg);
3656
+
3657
+ static const char * whitelist[] = {
3658
+ // Node options
3659
+ " -r" , " --require" ,
3660
+ " --no-deprecation" ,
3661
+ " --no-warnings" ,
3662
+ " --trace-warnings" ,
3663
+ " --redirect-warnings" ,
3664
+ " --trace-deprecation" ,
3665
+ " --trace-sync-io" ,
3666
+ " --trace-events-enabled" ,
3667
+ " --track-heap-objects" ,
3668
+ " --throw-deprecation" ,
3669
+ " --zero-fill-buffers" ,
3670
+ " --v8-pool-size" ,
3671
+ " --use-openssl-ca" ,
3672
+ " --use-bundled-ca" ,
3673
+ " --enable-fips" ,
3674
+ " --force-fips" ,
3675
+ " --openssl-config" ,
3676
+ " --icu-data-dir" ,
3677
+
3678
+ // V8 options
3679
+ " --max_old_space_size" ,
3680
+ };
3681
+
3682
+ for (unsigned i = 0 ; i < arraysize (whitelist); i++) {
3683
+ const char * allowed = whitelist[i];
3684
+ if (strlen (allowed) == arglen && strncmp (allowed, arg, arglen) == 0 )
3685
+ return ;
3686
+ }
3687
+
3688
+ fprintf (stderr, " %s: %s is not allowed in NODE_OPTIONS\n " , exe, arg);
3689
+ exit (9 );
3690
+ }
3691
+
3692
+
3645
3693
// Parse command line arguments.
3646
3694
//
3647
3695
// argv is modified in place. exec_argv and v8_argv are out arguments that
@@ -3658,7 +3706,8 @@ static void ParseArgs(int* argc,
3658
3706
int * exec_argc,
3659
3707
const char *** exec_argv,
3660
3708
int * v8_argc,
3661
- const char *** v8_argv) {
3709
+ const char *** v8_argv,
3710
+ bool is_env) {
3662
3711
const unsigned int nargs = static_cast <unsigned int >(*argc);
3663
3712
const char ** new_exec_argv = new const char *[nargs];
3664
3713
const char ** new_v8_argv = new const char *[nargs];
@@ -3687,6 +3736,8 @@ static void ParseArgs(int* argc,
3687
3736
const char * const arg = argv[index ];
3688
3737
unsigned int args_consumed = 1 ;
3689
3738
3739
+ CheckIfAllowedInEnv (argv[0 ], is_env, arg);
3740
+
3690
3741
if (debug_options.ParseOption (arg)) {
3691
3742
// Done, consumed by DebugOptions::ParseOption().
3692
3743
} else if (strcmp (arg, " --version" ) == 0 || strcmp (arg, " -v" ) == 0 ) {
@@ -3839,6 +3890,13 @@ static void ParseArgs(int* argc,
3839
3890
3840
3891
// Copy remaining arguments.
3841
3892
const unsigned int args_left = nargs - index ;
3893
+
3894
+ if (is_env && args_left) {
3895
+ fprintf (stderr, " %s: %s is not supported in NODE_OPTIONS\n " ,
3896
+ argv[0 ], argv[index ]);
3897
+ exit (9 );
3898
+ }
3899
+
3842
3900
memcpy (new_argv + new_argc, argv + index , args_left * sizeof (*argv));
3843
3901
new_argc += args_left;
3844
3902
@@ -4161,6 +4219,54 @@ inline void PlatformInit() {
4161
4219
}
4162
4220
4163
4221
4222
+ void ProcessArgv (int * argc,
4223
+ const char ** argv,
4224
+ int * exec_argc,
4225
+ const char *** exec_argv,
4226
+ bool is_env = false ) {
4227
+ // Parse a few arguments which are specific to Node.
4228
+ int v8_argc;
4229
+ const char ** v8_argv;
4230
+ ParseArgs (argc, argv, exec_argc, exec_argv, &v8_argc, &v8_argv, is_env);
4231
+
4232
+ // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler
4233
+ // manually? That would give us a little more control over its runtime
4234
+ // behavior but it could also interfere with the user's intentions in ways
4235
+ // we fail to anticipate. Dillema.
4236
+ for (int i = 1 ; i < v8_argc; ++i) {
4237
+ if (strncmp (v8_argv[i], " --prof" , sizeof (" --prof" ) - 1 ) == 0 ) {
4238
+ v8_is_profiling = true ;
4239
+ break ;
4240
+ }
4241
+ }
4242
+
4243
+ #ifdef __POSIX__
4244
+ // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the
4245
+ // performance penalty of frequent EINTR wakeups when the profiler is running.
4246
+ // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
4247
+ if (v8_is_profiling) {
4248
+ uv_loop_configure (uv_default_loop (), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
4249
+ }
4250
+ #endif
4251
+
4252
+ // The const_cast doesn't violate conceptual const-ness. V8 doesn't modify
4253
+ // the argv array or the elements it points to.
4254
+ if (v8_argc > 1 )
4255
+ V8::SetFlagsFromCommandLine (&v8_argc, const_cast <char **>(v8_argv), true );
4256
+
4257
+ // Anything that's still in v8_argv is not a V8 or a node option.
4258
+ for (int i = 1 ; i < v8_argc; i++) {
4259
+ fprintf (stderr, " %s: bad option: %s\n " , argv[0 ], v8_argv[i]);
4260
+ }
4261
+ delete[] v8_argv;
4262
+ v8_argv = nullptr ;
4263
+
4264
+ if (v8_argc > 1 ) {
4265
+ exit (9 );
4266
+ }
4267
+ }
4268
+
4269
+
4164
4270
void Init (int * argc,
4165
4271
const char ** argv,
4166
4272
int * exec_argc,
@@ -4214,31 +4320,36 @@ void Init(int* argc,
4214
4320
SafeGetenv (" OPENSSL_CONF" , &openssl_config);
4215
4321
#endif
4216
4322
4217
- // Parse a few arguments which are specific to Node.
4218
- int v8_argc;
4219
- const char ** v8_argv;
4220
- ParseArgs (argc, argv, exec_argc, exec_argv, &v8_argc, &v8_argv);
4221
-
4222
- // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler
4223
- // manually? That would give us a little more control over its runtime
4224
- // behavior but it could also interfere with the user's intentions in ways
4225
- // we fail to anticipate. Dillema.
4226
- for (int i = 1 ; i < v8_argc; ++i) {
4227
- if (strncmp (v8_argv[i], " --prof" , sizeof (" --prof" ) - 1 ) == 0 ) {
4228
- v8_is_profiling = true ;
4229
- break ;
4323
+ #if !defined(NODE_WITHOUT_NODE_OPTIONS)
4324
+ std::string node_options;
4325
+ if (SafeGetenv (" NODE_OPTIONS" , &node_options)) {
4326
+ // Smallest tokens are 2-chars (a not space and a space), plus 2 extra
4327
+ // pointers, for the prepended executable name, and appended NULL pointer.
4328
+ size_t max_len = 2 + (node_options.length () + 1 ) / 2 ;
4329
+ const char ** argv_from_env = new const char *[max_len];
4330
+ int argc_from_env = 0 ;
4331
+ // [0] is expected to be the program name, fill it in from the real argv.
4332
+ argv_from_env[argc_from_env++] = argv[0 ];
4333
+
4334
+ char * cstr = strdup (node_options.c_str ());
4335
+ char * initptr = cstr;
4336
+ char * token;
4337
+ while ((token = strtok (initptr, " " ))) { // NOLINT(runtime/threadsafe_fn)
4338
+ initptr = nullptr ;
4339
+ argv_from_env[argc_from_env++] = token;
4230
4340
}
4231
- }
4232
-
4233
- #ifdef __POSIX__
4234
- // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the
4235
- // performance penalty of frequent EINTR wakeups when the profiler is running.
4236
- // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
4237
- if (v8_is_profiling) {
4238
- uv_loop_configure (uv_default_loop (), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
4341
+ argv_from_env[argc_from_env] = nullptr ;
4342
+ int exec_argc_;
4343
+ const char ** exec_argv_ = nullptr ;
4344
+ ProcessArgv (&argc_from_env, argv_from_env, &exec_argc_, &exec_argv_, true );
4345
+ delete[] exec_argv_;
4346
+ delete[] argv_from_env;
4347
+ free (cstr);
4239
4348
}
4240
4349
#endif
4241
4350
4351
+ ProcessArgv (argc, argv, exec_argc, exec_argv);
4352
+
4242
4353
#if defined(NODE_HAVE_I18N_SUPPORT)
4243
4354
// If the parameter isn't given, use the env variable.
4244
4355
if (icu_data_dir.empty ())
@@ -4250,21 +4361,6 @@ void Init(int* argc,
4250
4361
" (check NODE_ICU_DATA or --icu-data-dir parameters)" );
4251
4362
}
4252
4363
#endif
4253
- // The const_cast doesn't violate conceptual const-ness. V8 doesn't modify
4254
- // the argv array or the elements it points to.
4255
- if (v8_argc > 1 )
4256
- V8::SetFlagsFromCommandLine (&v8_argc, const_cast <char **>(v8_argv), true );
4257
-
4258
- // Anything that's still in v8_argv is not a V8 or a node option.
4259
- for (int i = 1 ; i < v8_argc; i++) {
4260
- fprintf (stderr, " %s: bad option: %s\n " , argv[0 ], v8_argv[i]);
4261
- }
4262
- delete[] v8_argv;
4263
- v8_argv = nullptr ;
4264
-
4265
- if (v8_argc > 1 ) {
4266
- exit (9 );
4267
- }
4268
4364
4269
4365
// Unconditionally force typed arrays to allocate outside the v8 heap. This
4270
4366
// is to prevent memory pointers from being moved around that are returned by
0 commit comments