@@ -3552,6 +3552,9 @@ static void PrintHelp() {
3552
3552
#endif
3553
3553
#endif
3554
3554
" NODE_NO_WARNINGS set to 1 to silence process warnings\n "
3555
+ #if !defined(NODE_WITHOUT_NODE_OPTIONS)
3556
+ " NODE_OPTIONS set CLI options in the environment\n "
3557
+ #endif
3555
3558
#ifdef _WIN32
3556
3559
" NODE_PATH ';'-separated list of directories\n "
3557
3560
#else
@@ -3566,6 +3569,51 @@ static void PrintHelp() {
3566
3569
}
3567
3570
3568
3571
3572
+ static void CheckIfAllowedInEnv (const char * exe, bool is_env,
3573
+ const char * arg) {
3574
+ if (!is_env)
3575
+ return ;
3576
+
3577
+ // Find the arg prefix when its --some_arg=val
3578
+ const char * eq = strchr (arg, ' =' );
3579
+ size_t arglen = eq ? eq - arg : strlen (arg);
3580
+
3581
+ static const char * whitelist[] = {
3582
+ // Node options
3583
+ " -r" , " --require" ,
3584
+ " --no-deprecation" ,
3585
+ " --no-warnings" ,
3586
+ " --trace-warnings" ,
3587
+ " --redirect-warnings" ,
3588
+ " --trace-deprecation" ,
3589
+ " --trace-sync-io" ,
3590
+ " --trace-events-enabled" ,
3591
+ " --track-heap-objects" ,
3592
+ " --throw-deprecation" ,
3593
+ " --zero-fill-buffers" ,
3594
+ " --v8-pool-size" ,
3595
+ " --use-openssl-ca" ,
3596
+ " --use-bundled-ca" ,
3597
+ " --enable-fips" ,
3598
+ " --force-fips" ,
3599
+ " --openssl-config" ,
3600
+ " --icu-data-dir" ,
3601
+
3602
+ // V8 options
3603
+ " --max_old_space_size" ,
3604
+ };
3605
+
3606
+ for (unsigned i = 0 ; i < arraysize (whitelist); i++) {
3607
+ const char * allowed = whitelist[i];
3608
+ if (strlen (allowed) == arglen && strncmp (allowed, arg, arglen) == 0 )
3609
+ return ;
3610
+ }
3611
+
3612
+ fprintf (stderr, " %s: %s is not allowed in NODE_OPTIONS\n " , exe, arg);
3613
+ exit (9 );
3614
+ }
3615
+
3616
+
3569
3617
// Parse command line arguments.
3570
3618
//
3571
3619
// argv is modified in place. exec_argv and v8_argv are out arguments that
@@ -3582,7 +3630,8 @@ static void ParseArgs(int* argc,
3582
3630
int * exec_argc,
3583
3631
const char *** exec_argv,
3584
3632
int * v8_argc,
3585
- const char *** v8_argv) {
3633
+ const char *** v8_argv,
3634
+ bool is_env) {
3586
3635
const unsigned int nargs = static_cast <unsigned int >(*argc);
3587
3636
const char ** new_exec_argv = new const char *[nargs];
3588
3637
const char ** new_v8_argv = new const char *[nargs];
@@ -3609,6 +3658,8 @@ static void ParseArgs(int* argc,
3609
3658
const char * const arg = argv[index];
3610
3659
unsigned int args_consumed = 1 ;
3611
3660
3661
+ CheckIfAllowedInEnv (argv[0 ], is_env, arg);
3662
+
3612
3663
if (debug_options.ParseOption (arg)) {
3613
3664
// Done, consumed by DebugOptions::ParseOption().
3614
3665
} else if (strcmp (arg, " --version" ) == 0 || strcmp (arg, " -v" ) == 0 ) {
@@ -3737,6 +3788,13 @@ static void ParseArgs(int* argc,
3737
3788
3738
3789
// Copy remaining arguments.
3739
3790
const unsigned int args_left = nargs - index;
3791
+
3792
+ if (is_env && args_left) {
3793
+ fprintf (stderr, " %s: %s is not supported in NODE_OPTIONS\n " ,
3794
+ argv[0 ], argv[index]);
3795
+ exit (9 );
3796
+ }
3797
+
3740
3798
memcpy (new_argv + new_argc, argv + index, args_left * sizeof (*argv));
3741
3799
new_argc += args_left;
3742
3800
@@ -4180,6 +4238,54 @@ inline void PlatformInit() {
4180
4238
}
4181
4239
4182
4240
4241
+ void ProcessArgv (int * argc,
4242
+ const char ** argv,
4243
+ int * exec_argc,
4244
+ const char *** exec_argv,
4245
+ bool is_env = false ) {
4246
+ // Parse a few arguments which are specific to Node.
4247
+ int v8_argc;
4248
+ const char ** v8_argv;
4249
+ ParseArgs (argc, argv, exec_argc, exec_argv, &v8_argc, &v8_argv, is_env);
4250
+
4251
+ // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler
4252
+ // manually? That would give us a little more control over its runtime
4253
+ // behavior but it could also interfere with the user's intentions in ways
4254
+ // we fail to anticipate. Dillema.
4255
+ for (int i = 1 ; i < v8_argc; ++i) {
4256
+ if (strncmp (v8_argv[i], " --prof" , sizeof (" --prof" ) - 1 ) == 0 ) {
4257
+ v8_is_profiling = true ;
4258
+ break ;
4259
+ }
4260
+ }
4261
+
4262
+ #ifdef __POSIX__
4263
+ // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the
4264
+ // performance penalty of frequent EINTR wakeups when the profiler is running.
4265
+ // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
4266
+ if (v8_is_profiling) {
4267
+ uv_loop_configure (uv_default_loop (), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
4268
+ }
4269
+ #endif
4270
+
4271
+ // The const_cast doesn't violate conceptual const-ness. V8 doesn't modify
4272
+ // the argv array or the elements it points to.
4273
+ if (v8_argc > 1 )
4274
+ V8::SetFlagsFromCommandLine (&v8_argc, const_cast <char **>(v8_argv), true );
4275
+
4276
+ // Anything that's still in v8_argv is not a V8 or a node option.
4277
+ for (int i = 1 ; i < v8_argc; i++) {
4278
+ fprintf (stderr, " %s: bad option: %s\n " , argv[0 ], v8_argv[i]);
4279
+ }
4280
+ delete[] v8_argv;
4281
+ v8_argv = nullptr ;
4282
+
4283
+ if (v8_argc > 1 ) {
4284
+ exit (9 );
4285
+ }
4286
+ }
4287
+
4288
+
4183
4289
void Init (int * argc,
4184
4290
const char ** argv,
4185
4291
int * exec_argc,
@@ -4222,31 +4328,36 @@ void Init(int* argc,
4222
4328
if (openssl_config.empty ())
4223
4329
SafeGetenv (" OPENSSL_CONF" , &openssl_config);
4224
4330
4225
- // Parse a few arguments which are specific to Node.
4226
- int v8_argc;
4227
- const char ** v8_argv;
4228
- ParseArgs (argc, argv, exec_argc, exec_argv, &v8_argc, &v8_argv);
4229
-
4230
- // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler
4231
- // manually? That would give us a little more control over its runtime
4232
- // behavior but it could also interfere with the user's intentions in ways
4233
- // we fail to anticipate. Dillema.
4234
- for (int i = 1 ; i < v8_argc; ++i) {
4235
- if (strncmp (v8_argv[i], " --prof" , sizeof (" --prof" ) - 1 ) == 0 ) {
4236
- v8_is_profiling = true ;
4237
- break ;
4331
+ #if !defined(NODE_WITHOUT_NODE_OPTIONS)
4332
+ std::string node_options;
4333
+ if (SafeGetenv (" NODE_OPTIONS" , &node_options)) {
4334
+ // Smallest tokens are 2-chars (a not space and a space), plus 2 extra
4335
+ // pointers, for the prepended executable name, and appended NULL pointer.
4336
+ size_t max_len = 2 + (node_options.length () + 1 ) / 2 ;
4337
+ const char ** argv_from_env = new const char *[max_len];
4338
+ int argc_from_env = 0 ;
4339
+ // [0] is expected to be the program name, fill it in from the real argv.
4340
+ argv_from_env[argc_from_env++] = argv[0 ];
4341
+
4342
+ char * cstr = strdup (node_options.c_str ());
4343
+ char * initptr = cstr;
4344
+ char * token;
4345
+ while ((token = strtok (initptr, " " ))) { // NOLINT(runtime/threadsafe_fn)
4346
+ initptr = nullptr ;
4347
+ argv_from_env[argc_from_env++] = token;
4238
4348
}
4239
- }
4240
-
4241
- #ifdef __POSIX__
4242
- // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the
4243
- // performance penalty of frequent EINTR wakeups when the profiler is running.
4244
- // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users.
4245
- if (v8_is_profiling) {
4246
- uv_loop_configure (uv_default_loop (), UV_LOOP_BLOCK_SIGNAL, SIGPROF);
4349
+ argv_from_env[argc_from_env] = nullptr ;
4350
+ int exec_argc_;
4351
+ const char ** exec_argv_ = nullptr ;
4352
+ ProcessArgv (&argc_from_env, argv_from_env, &exec_argc_, &exec_argv_, true );
4353
+ delete[] exec_argv_;
4354
+ delete[] argv_from_env;
4355
+ free (cstr);
4247
4356
}
4248
4357
#endif
4249
4358
4359
+ ProcessArgv (argc, argv, exec_argc, exec_argv);
4360
+
4250
4361
#if defined(NODE_HAVE_I18N_SUPPORT)
4251
4362
// If the parameter isn't given, use the env variable.
4252
4363
if (icu_data_dir.empty ())
@@ -4258,21 +4369,6 @@ void Init(int* argc,
4258
4369
" (check NODE_ICU_DATA or --icu-data-dir parameters)" );
4259
4370
}
4260
4371
#endif
4261
- // The const_cast doesn't violate conceptual const-ness. V8 doesn't modify
4262
- // the argv array or the elements it points to.
4263
- if (v8_argc > 1 )
4264
- V8::SetFlagsFromCommandLine (&v8_argc, const_cast <char **>(v8_argv), true );
4265
-
4266
- // Anything that's still in v8_argv is not a V8 or a node option.
4267
- for (int i = 1 ; i < v8_argc; i++) {
4268
- fprintf (stderr, " %s: bad option: %s\n " , argv[0 ], v8_argv[i]);
4269
- }
4270
- delete[] v8_argv;
4271
- v8_argv = nullptr ;
4272
-
4273
- if (v8_argc > 1 ) {
4274
- exit (9 );
4275
- }
4276
4372
4277
4373
// Unconditionally force typed arrays to allocate outside the v8 heap. This
4278
4374
// is to prevent memory pointers from being moved around that are returned by
0 commit comments