| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 8f42148 commit dd6ea89
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -444,6 +444,11 @@ parser.add_option('--without-ssl', | |||
| 444 | 444 | dest='without_ssl', | |
| 445 | 445 | help='build without SSL (disables crypto, https, inspector, etc.)') | |
| 446 | 446 | ||
| 447 | + parser.add_option('--without-node-options', | ||
| 448 | + action='store_true', | ||
| 449 | + dest='without_node_options', | ||
| 450 | + help='build without NODE_OPTIONS support') | ||
| 451 | + | ||
| 447 | 452 | parser.add_option('--xcode', | |
| 448 | 453 | action='store_true', | |
| 449 | 454 | dest='use_xcode', | |
@@ -975,6 +980,9 @@ def configure_openssl(o): | |||
| 975 | 980 | o['variables']['openssl_no_asm'] = 1 if options.openssl_no_asm else 0 | |
| 976 | 981 | if options.use_openssl_ca_store: | |
| 977 | 982 | o['defines'] += ['NODE_OPENSSL_CERT_STORE'] | |
| 983 | + o['variables']['node_without_node_options'] = b(options.without_node_options) | ||
| 984 | + if options.without_node_options: | ||
| 985 | + o['defines'] += ['NODE_WITHOUT_NODE_OPTIONS'] | ||
| 978 | 986 | if options.openssl_fips: | |
| 979 | 987 | o['variables']['openssl_fips'] = options.openssl_fips | |
| 980 | 988 | fips_dir = os.path.join(root_dir, 'deps', 'openssl', 'fips') | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -332,6 +332,41 @@ added: v6.11.0 | |||
| 332 | 332 | ||
| 333 | 333 | When set to `1`, process warnings are silenced. | |
| 334 | 334 | ||
| 335 | + ### `NODE_OPTIONS=options...` | ||
| 336 | + <!-- YAML | ||
| 337 | + added: REPLACEME | ||
| 338 | + --> | ||
| 339 | + | ||
| 340 | + `options...` are interpreted as if they had been specified on the command line | ||
| 341 | + before the actual command line (so they can be overriden). Node will exit with | ||
| 342 | + an error if an option that is not allowed in the environment is used, such as | ||
| 343 | + `-p` or a script file. | ||
| 344 | + | ||
| 345 | + Node options that are allowed are: | ||
| 346 | + - `--enable-fips` | ||
| 347 | + - `--force-fips` | ||
| 348 | + - `--icu-data-dir` | ||
| 349 | + - `--no-deprecation` | ||
| 350 | + - `--no-warnings` | ||
| 351 | + - `--openssl-config` | ||
| 352 | + - `--prof-process` | ||
| 353 | + - `--redirect-warnings` | ||
| 354 | + - `--require`, `-r` | ||
| 355 | + - `--throw-deprecation` | ||
| 356 | + - `--trace-deprecation` | ||
| 357 | + - `--trace-events-enabled` | ||
| 358 | + - `--trace-sync-io` | ||
| 359 | + - `--trace-warnings` | ||
| 360 | + - `--track-heap-objects` | ||
| 361 | + - `--use-bundled-ca` | ||
| 362 | + - `--use-openssl-ca` | ||
| 363 | + - `--v8-pool-size` | ||
| 364 | + - `--zero-fill-buffers` | ||
| 365 | + | ||
| 366 | + V8 options that are allowed are: | ||
| 367 | + - `--max_old_space_size` | ||
| 368 | + | ||
| 369 | + | ||
| 335 | 370 | ### `NODE_REPL_HISTORY=file` | |
| 336 | 371 | <!-- YAML | |
| 337 | 372 | added: v3.0.0 | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -226,6 +226,13 @@ with small\-icu support. | |||
| 226 | 226 | .BR NODE_NO_WARNINGS =\fI1\fR | |
| 227 | 227 | When set to \fI1\fR, process warnings are silenced. | |
| 228 | 228 | ||
| 229 | + .TP | ||
| 230 | + .BR NODE_OPTIONS =\fIoptions...\fR | ||
| 231 | + \fBoptions...\fR are interpreted as if they had been specified on the command | ||
| 232 | + line before the actual command line (so they can be overriden). Node will exit | ||
| 233 | + with an error if an option that is not allowed in the environment is used, such | ||
| 234 | + as \fB-p\fR or a script file. | ||
| 235 | + | ||
| 229 | 236 | .TP | |
| 230 | 237 | .BR NODE_REPL_HISTORY =\fIfile\fR | |
| 231 | 238 | Path to the file used to store the persistent REPL history. The default path | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3759,6 +3759,9 @@ static void PrintHelp() { | |||
| 3759 | 3759 | #endif | |
| 3760 | 3760 | #endif | |
| 3761 | 3761 | "NODE_NO_WARNINGS set to 1 to silence process warnings\n" | |
| 3762 | + #if !defined(NODE_WITHOUT_NODE_OPTIONS) | ||
| 3763 | + "NODE_OPTIONS set CLI options in the environment\n" | ||
| 3764 | + #endif | ||
| 3762 | 3765 | #ifdef _WIN32 | |
| 3763 | 3766 | "NODE_PATH ';'-separated list of directories\n" | |
| 3764 | 3767 | #else | |
@@ -3773,6 +3776,50 @@ static void PrintHelp() { | |||
| 3773 | 3776 | } | |
| 3774 | 3777 | ||
| 3775 | 3778 | ||
| 3779 | + static void CheckIfAllowedInEnv(const char* exe, bool is_env, | ||
| 3780 | + const char* arg) { | ||
| 3781 | + if (!is_env) | ||
| 3782 | + return; | ||
| 3783 | + | ||
| 3784 | + // Find the arg prefix when its --some_arg=val | ||
| 3785 | + const char* eq = strchr(arg, '='); | ||
| 3786 | + size_t arglen = eq ? eq - arg : strlen(arg); | ||
| 3787 | + | ||
| 3788 | + static const char* whitelist[] = { | ||
| 3789 | + // Node options | ||
| 3790 | + "-r", "--require", | ||
| 3791 | + "--no-deprecation", | ||
| 3792 | + "--no-warnings", | ||
| 3793 | + "--trace-warnings", | ||
| 3794 | + "--redirect-warnings", | ||
| 3795 | + "--trace-deprecation", | ||
| 3796 | + "--trace-sync-io", | ||
| 3797 | + "--track-heap-objects", | ||
| 3798 | + "--throw-deprecation", | ||
| 3799 | + "--zero-fill-buffers", | ||
| 3800 | + "--v8-pool-size", | ||
| 3801 | + "--use-openssl-ca", | ||
| 3802 | + "--use-bundled-ca", | ||
| 3803 | + "--enable-fips", | ||
| 3804 | + "--force-fips", | ||
| 3805 | + "--openssl-config", | ||
| 3806 | + "--icu-data-dir", | ||
| 3807 | + | ||
| 3808 | + // V8 options | ||
| 3809 | + "--max_old_space_size", | ||
| 3810 | + }; | ||
| 3811 | + | ||
| 3812 | + for (unsigned i = 0; i < arraysize(whitelist); i++) { | ||
| 3813 | + const char* allowed = whitelist[i]; | ||
| 3814 | + if (strlen(allowed) == arglen && strncmp(allowed, arg, arglen) == 0) | ||
| 3815 | + return; | ||
| 3816 | + } | ||
| 3817 | + | ||
| 3818 | + fprintf(stderr, "%s: %s is not allowed in NODE_OPTIONS\n", exe, arg); | ||
| 3819 | + exit(9); | ||
| 3820 | + } | ||
| 3821 | + | ||
| 3822 | + | ||
| 3776 | 3823 | // Parse command line arguments. | |
| 3777 | 3824 | // | |
| 3778 | 3825 | // argv is modified in place. exec_argv and v8_argv are out arguments that | |
@@ -3789,7 +3836,8 @@ static void ParseArgs(int* argc, | |||
| 3789 | 3836 | int* exec_argc, | |
| 3790 | 3837 | const char*** exec_argv, | |
| 3791 | 3838 | int* v8_argc, | |
| 3792 | - const char*** v8_argv) { | ||
| 3839 | + const char*** v8_argv, | ||
| 3840 | + bool is_env) { | ||
| 3793 | 3841 | const unsigned int nargs = static_cast<unsigned int>(*argc); | |
| 3794 | 3842 | const char** new_exec_argv = new const char*[nargs]; | |
| 3795 | 3843 | const char** new_v8_argv = new const char*[nargs]; | |
@@ -3814,6 +3862,8 @@ static void ParseArgs(int* argc, | |||
| 3814 | 3862 | const char* const arg = argv[index]; | |
| 3815 | 3863 | unsigned int args_consumed = 1; | |
| 3816 | 3864 | ||
| 3865 | + CheckIfAllowedInEnv(argv[0], is_env, arg); | ||
| 3866 | + | ||
| 3817 | 3867 | if (ParseDebugOpt(arg)) { | |
| 3818 | 3868 | // Done, consumed by ParseDebugOpt(). | |
| 3819 | 3869 | } else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) { | |
@@ -3934,6 +3984,13 @@ static void ParseArgs(int* argc, | |||
| 3934 | 3984 | ||
| 3935 | 3985 | // Copy remaining arguments. | |
| 3936 | 3986 | const unsigned int args_left = nargs - index; | |
| 3987 | + | ||
| 3988 | + if (is_env && args_left) { | ||
| 3989 | + fprintf(stderr, "%s: %s is not supported in NODE_OPTIONS\n", | ||
| 3990 | + argv[0], argv[index]); | ||
| 3991 | + exit(9); | ||
| 3992 | + } | ||
| 3993 | + | ||
| 3937 | 3994 | memcpy(new_argv + new_argc, argv + index, args_left * sizeof(*argv)); | |
| 3938 | 3995 | new_argc += args_left; | |
| 3939 | 3996 | ||
@@ -4367,6 +4424,54 @@ inline void PlatformInit() { | |||
| 4367 | 4424 | } | |
| 4368 | 4425 | ||
| 4369 | 4426 | ||
| 4427 | + void ProcessArgv(int* argc, | ||
| 4428 | + const char** argv, | ||
| 4429 | + int* exec_argc, | ||
| 4430 | + const char*** exec_argv, | ||
| 4431 | + bool is_env = false) { | ||
| 4432 | + // Parse a few arguments which are specific to Node. | ||
| 4433 | + int v8_argc; | ||
| 4434 | + const char** v8_argv; | ||
| 4435 | + ParseArgs(argc, argv, exec_argc, exec_argv, &v8_argc, &v8_argv, is_env); | ||
| 4436 | + | ||
| 4437 | + // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler | ||
| 4438 | + // manually? That would give us a little more control over its runtime | ||
| 4439 | + // behavior but it could also interfere with the user's intentions in ways | ||
| 4440 | + // we fail to anticipate. Dillema. | ||
| 4441 | + for (int i = 1; i < v8_argc; ++i) { | ||
| 4442 | + if (strncmp(v8_argv[i], "--prof", sizeof("--prof") - 1) == 0) { | ||
| 4443 | + v8_is_profiling = true; | ||
| 4444 | + break; | ||
| 4445 | + } | ||
| 4446 | + } | ||
| 4447 | + | ||
| 4448 | + #ifdef __POSIX__ | ||
| 4449 | + // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the | ||
| 4450 | + // performance penalty of frequent EINTR wakeups when the profiler is running. | ||
| 4451 | + // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users. | ||
| 4452 | + if (v8_is_profiling) { | ||
| 4453 | + uv_loop_configure(uv_default_loop(), UV_LOOP_BLOCK_SIGNAL, SIGPROF); | ||
| 4454 | + } | ||
| 4455 | + #endif | ||
| 4456 | + | ||
| 4457 | + // The const_cast doesn't violate conceptual const-ness. V8 doesn't modify | ||
| 4458 | + // the argv array or the elements it points to. | ||
| 4459 | + if (v8_argc > 1) | ||
| 4460 | + V8::SetFlagsFromCommandLine(&v8_argc, const_cast<char**>(v8_argv), true); | ||
| 4461 | + | ||
| 4462 | + // Anything that's still in v8_argv is not a V8 or a node option. | ||
| 4463 | + for (int i = 1; i < v8_argc; i++) { | ||
| 4464 | + fprintf(stderr, "%s: bad option: %s\n", argv[0], v8_argv[i]); | ||
| 4465 | + } | ||
| 4466 | + delete[] v8_argv; | ||
| 4467 | + v8_argv = nullptr; | ||
| 4468 | + | ||
| 4469 | + if (v8_argc > 1) { | ||
| 4470 | + exit(9); | ||
| 4471 | + } | ||
| 4472 | + } | ||
| 4473 | + | ||
| 4474 | + | ||
| 4370 | 4475 | void Init(int* argc, | |
| 4371 | 4476 | const char** argv, | |
| 4372 | 4477 | int* exec_argc, | |
@@ -4397,31 +4502,36 @@ void Init(int* argc, | |||
| 4397 | 4502 | if (config_warning_file.empty()) | |
| 4398 | 4503 | SafeGetenv("NODE_REDIRECT_WARNINGS", &config_warning_file); | |
| 4399 | 4504 | ||
| 4400 | - // Parse a few arguments which are specific to Node. | ||
| 4401 | - int v8_argc; | ||
| 4402 | - const char** v8_argv; | ||
| 4403 | - ParseArgs(argc, argv, exec_argc, exec_argv, &v8_argc, &v8_argv); | ||
| 4404 | - | ||
| 4405 | - // TODO(bnoordhuis) Intercept --prof arguments and start the CPU profiler | ||
| 4406 | - // manually? That would give us a little more control over its runtime | ||
| 4407 | - // behavior but it could also interfere with the user's intentions in ways | ||
| 4408 | - // we fail to anticipate. Dillema. | ||
| 4409 | - for (int i = 1; i < v8_argc; ++i) { | ||
| 4410 | - if (strncmp(v8_argv[i], "--prof", sizeof("--prof") - 1) == 0) { | ||
| 4411 | - v8_is_profiling = true; | ||
| 4412 | - break; | ||
| 4505 | + #if !defined(NODE_WITHOUT_NODE_OPTIONS) | ||
| 4506 | + std::string node_options; | ||
| 4507 | + if (SafeGetenv("NODE_OPTIONS", &node_options)) { | ||
| 4508 | + // Smallest tokens are 2-chars (a not space and a space), plus 2 extra | ||
| 4509 | + // pointers, for the prepended executable name, and appended NULL pointer. | ||
| 4510 | + size_t max_len = 2 + (node_options.length() + 1) / 2; | ||
| 4511 | + const char** argv_from_env = new const char*[max_len]; | ||
| 4512 | + int argc_from_env = 0; | ||
| 4513 | + // [0] is expected to be the program name, fill it in from the real argv. | ||
| 4514 | + argv_from_env[argc_from_env++] = argv[0]; | ||
| 4515 | + | ||
| 4516 | + char* cstr = strdup(node_options.c_str()); | ||
| 4517 | + char* initptr = cstr; | ||
| 4518 | + char* token; | ||
| 4519 | + while ((token = strtok(initptr, " "))) { // NOLINT(runtime/threadsafe_fn) | ||
| 4520 | + initptr = nullptr; | ||
| 4521 | + argv_from_env[argc_from_env++] = token; | ||
| 4413 | 4522 | } | |
| 4414 | - } | ||
| 4415 | - | ||
| 4416 | - #ifdef __POSIX__ | ||
| 4417 | - // Block SIGPROF signals when sleeping in epoll_wait/kevent/etc. Avoids the | ||
| 4418 | - // performance penalty of frequent EINTR wakeups when the profiler is running. | ||
| 4419 | - // Only do this for v8.log profiling, as it breaks v8::CpuProfiler users. | ||
| 4420 | - if (v8_is_profiling) { | ||
| 4421 | - uv_loop_configure(uv_default_loop(), UV_LOOP_BLOCK_SIGNAL, SIGPROF); | ||
| 4523 | + argv_from_env[argc_from_env] = nullptr; | ||
| 4524 | + int exec_argc_; | ||
| 4525 | + const char** exec_argv_ = nullptr; | ||
| 4526 | + ProcessArgv(&argc_from_env, argv_from_env, &exec_argc_, &exec_argv_, true); | ||
| 4527 | + delete[] exec_argv_; | ||
| 4528 | + delete[] argv_from_env; | ||
| 4529 | + free(cstr); | ||
| 4422 | 4530 | } | |
| 4423 | 4531 | #endif | |
| 4424 | 4532 | ||
| 4533 | + ProcessArgv(argc, argv, exec_argc, exec_argv); | ||
| 4534 | + | ||
| 4425 | 4535 | #if defined(NODE_HAVE_I18N_SUPPORT) | |
| 4426 | 4536 | // If the parameter isn't given, use the env variable. | |
| 4427 | 4537 | if (icu_data_dir.empty()) | |
@@ -4433,21 +4543,6 @@ void Init(int* argc, | |||
| 4433 | 4543 | "(check NODE_ICU_DATA or --icu-data-dir parameters)\n"); | |
| 4434 | 4544 | } | |
| 4435 | 4545 | #endif | |
| 4436 | - // The const_cast doesn't violate conceptual const-ness. V8 doesn't modify | ||
| 4437 | - // the argv array or the elements it points to. | ||
| 4438 | - if (v8_argc > 1) | ||
| 4439 | - V8::SetFlagsFromCommandLine(&v8_argc, const_cast<char**>(v8_argv), true); | ||
| 4440 | - | ||
| 4441 | - // Anything that's still in v8_argv is not a V8 or a node option. | ||
| 4442 | - for (int i = 1; i < v8_argc; i++) { | ||
| 4443 | - fprintf(stderr, "%s: bad option: %s\n", argv[0], v8_argv[i]); | ||
| 4444 | - } | ||
| 4445 | - delete[] v8_argv; | ||
| 4446 | - v8_argv = nullptr; | ||
| 4447 | - | ||
| 4448 | - if (v8_argc > 1) { | ||
| 4449 | - exit(9); | ||
| 4450 | - } | ||
| 4451 | 4546 | ||
| 4452 | 4547 | // Unconditionally force typed arrays to allocate outside the v8 heap. This | |
| 4453 | 4548 | // is to prevent memory pointers from being moved around that are returned by | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,74 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + if (process.config.variables.node_without_node_options) | ||
| 4 | + return common.skip('missing NODE_OPTIONS support'); | ||
| 5 | + | ||
| 6 | + // Test options specified by env variable. | ||
| 7 | + | ||
| 8 | + const assert = require('assert'); | ||
| 9 | + const exec = require('child_process').execFile; | ||
| 10 | + | ||
| 11 | + disallow('--version'); | ||
| 12 | + disallow('-v'); | ||
| 13 | + disallow('--help'); | ||
| 14 | + disallow('-h'); | ||
| 15 | + disallow('--eval'); | ||
| 16 | + disallow('-e'); | ||
| 17 | + disallow('--print'); | ||
| 18 | + disallow('-p'); | ||
| 19 | + disallow('-pe'); | ||
| 20 | + disallow('--check'); | ||
| 21 | + disallow('-c'); | ||
| 22 | + disallow('--interactive'); | ||
| 23 | + disallow('-i'); | ||
| 24 | + disallow('--v8-options'); | ||
| 25 | + disallow('--'); | ||
| 26 | + | ||
| 27 | + function disallow(opt) { | ||
| 28 | + const options = {env: {NODE_OPTIONS: opt}}; | ||
| 29 | + exec(process.execPath, options, common.mustCall(function(err) { | ||
| 30 | + const message = err.message.split(/\r?\n/)[1]; | ||
| 31 | + const expect = process.execPath + ': ' + opt + | ||
| 32 | + ' is not allowed in NODE_OPTIONS'; | ||
| 33 | + | ||
| 34 | + assert.strictEqual(err.code, 9); | ||
| 35 | + assert.strictEqual(message, expect); | ||
| 36 | + })); | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + const printA = require.resolve('../fixtures/printA.js'); | ||
| 40 | + | ||
| 41 | + expect('-r ' + printA, 'A\nB\n'); | ||
| 42 | + expect('--no-deprecation', 'B\n'); | ||
| 43 | + expect('--no-warnings', 'B\n'); | ||
| 44 | + expect('--trace-warnings', 'B\n'); | ||
| 45 | + expect('--trace-deprecation', 'B\n'); | ||
| 46 | + expect('--trace-sync-io', 'B\n'); | ||
| 47 | + expect('--track-heap-objects', 'B\n'); | ||
| 48 | + expect('--throw-deprecation', 'B\n'); | ||
| 49 | + expect('--zero-fill-buffers', 'B\n'); | ||
| 50 | + expect('--v8-pool-size=10', 'B\n'); | ||
| 51 | + expect('--use-openssl-ca', 'B\n'); | ||
| 52 | + expect('--use-bundled-ca', 'B\n'); | ||
| 53 | + expect('--openssl-config=_ossl_cfg', 'B\n'); | ||
| 54 | + expect('--icu-data-dir=_d', 'B\n'); | ||
| 55 | + | ||
| 56 | + // V8 options | ||
| 57 | + expect('--max_old_space_size=0', 'B\n'); | ||
| 58 | + | ||
| 59 | + function expect(opt, want) { | ||
| 60 | + const printB = require.resolve('../fixtures/printB.js'); | ||
| 61 | + const argv = [printB]; | ||
| 62 | + const opts = { | ||
| 63 | + env: {NODE_OPTIONS: opt}, | ||
| 64 | + maxBuffer: 1000000000, | ||
| 65 | + }; | ||
| 66 | + exec(process.execPath, argv, opts, common.mustCall(function(err, stdout) { | ||
| 67 | + assert.ifError(err); | ||
| 68 | + if (!RegExp(want).test(stdout)) { | ||
| 69 | + console.error('For %j, failed to find %j in: <\n%s\n>', | ||
| 70 | + opt, expect, stdout); | ||
| 71 | + assert(false, 'Expected ' + expect); | ||
| 72 | + } | ||
| 73 | + })); | ||
| 74 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments