Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit a933103

Browse filesBrowse files
joyeecheungruyadorno
authored andcommitted
cli: implement --trace-env and --trace-env-[js|native]-stack
This implements --trace-env, --trace-env-js-stack and --trace-env-native-stack CLI options which can be used to find out what environment variables are accessed and where they are accessed. PR-URL: #55604 Reviewed-By: Chengzhong Wu <legendecas@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent ea48918 commit a933103
Copy full SHA for a933103

File tree

Expand file treeCollapse file tree

19 files changed

+365
-26
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

19 files changed

+365
-26
lines changed
Open diff view settings
Collapse file

‎doc/api/cli.md‎

Copy file name to clipboardExpand all lines: doc/api/cli.md
+42Lines changed: 42 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -2604,6 +2604,45 @@ added: v0.8.0
26042604

26052605
Print stack traces for deprecations.
26062606

2607+
### `--trace-env`
2608+
2609+
<!-- YAML
2610+
added: REPLACEME
2611+
-->
2612+
2613+
Print information about any access to environment variables done in the current Node.js
2614+
instance to stderr, including:
2615+
2616+
* The environment variable reads that Node.js does internally.
2617+
* Writes in the form of `process.env.KEY = "SOME VALUE"`.
2618+
* Reads in the form of `process.env.KEY`.
2619+
* Definitions in the form of `Object.defineProperty(process.env, 'KEY', {...})`.
2620+
* Queries in the form of `Object.hasOwn(process.env, 'KEY')`,
2621+
`process.env.hasOwnProperty('KEY')` or `'KEY' in process.env`.
2622+
* Deletions in the form of `delete process.env.KEY`.
2623+
* Enumerations inf the form of `...process.env` or `Object.keys(process.env)`.
2624+
2625+
Only the names of the environment variables being accessed are printed. The values are not printed.
2626+
2627+
To print the stack trace of the access, use `--trace-env-js-stack` and/or
2628+
`--trace-env-native-stack`.
2629+
2630+
### `--trace-env-js-stack`
2631+
2632+
<!-- YAML
2633+
added: REPLACEME
2634+
-->
2635+
2636+
In addition to what `--trace-env` does, this prints the JavaScript stack trace of the access.
2637+
2638+
### `--trace-env-native-stack`
2639+
2640+
<!-- YAML
2641+
added: REPLACEME
2642+
-->
2643+
2644+
In addition to what `--trace-env` does, this prints the native stack trace of the access.
2645+
26072646
### `--trace-event-categories`
26082647

26092648
<!-- YAML
@@ -3150,6 +3189,9 @@ one is included in the list below.
31503189
* `--tls-min-v1.3`
31513190
* `--trace-atomics-wait`
31523191
* `--trace-deprecation`
3192+
* `--trace-env-js-stack`
3193+
* `--trace-env-native-stack`
3194+
* `--trace-env`
31533195
* `--trace-event-categories`
31543196
* `--trace-event-file-pattern`
31553197
* `--trace-events-enabled`
Collapse file

‎src/debug_utils.cc‎

Copy file name to clipboardExpand all lines: src/debug_utils.cc
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ EnabledDebugList enabled_debug_list;
6262
using v8::Local;
6363
using v8::StackTrace;
6464

65-
void EnabledDebugList::Parse(std::shared_ptr<KVStore> env_vars) {
65+
void EnabledDebugList::Parse(Environment* env) {
6666
std::string cats;
67-
credentials::SafeGetenv("NODE_DEBUG_NATIVE", &cats, env_vars);
67+
credentials::SafeGetenv("NODE_DEBUG_NATIVE", &cats, env);
6868
Parse(cats);
6969
}
7070

Collapse file

‎src/debug_utils.h‎

Copy file name to clipboardExpand all lines: src/debug_utils.h
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,10 @@ class NODE_EXTERN_PRIVATE EnabledDebugList {
7474
return enabled_[static_cast<unsigned int>(category)];
7575
}
7676

77-
// Uses NODE_DEBUG_NATIVE to initialize the categories. The env_vars variable
77+
// Uses NODE_DEBUG_NATIVE to initialize the categories. env->env_vars()
7878
// is parsed if it is not a nullptr, otherwise the system environment
7979
// variables are parsed.
80-
void Parse(std::shared_ptr<KVStore> env_vars);
80+
void Parse(Environment* env);
8181

8282
private:
8383
// Enable all categories matching cats.
Collapse file

‎src/env.cc‎

Copy file name to clipboardExpand all lines: src/env.cc
+9-6Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -875,9 +875,6 @@ Environment::Environment(IsolateData* isolate_data,
875875
EnvironmentFlags::kOwnsInspector;
876876
}
877877

878-
set_env_vars(per_process::system_environment);
879-
enabled_debug_list_.Parse(env_vars());
880-
881878
// We create new copies of the per-Environment option sets, so that it is
882879
// easier to modify them after Environment creation. The defaults are
883880
// part of the per-Isolate option set, for which in turn the defaults are
@@ -887,6 +884,13 @@ Environment::Environment(IsolateData* isolate_data,
887884
inspector_host_port_ = std::make_shared<ExclusiveAccess<HostPort>>(
888885
options_->debug_options().host_port);
889886

887+
set_env_vars(per_process::system_environment);
888+
// This should be done after options is created, so that --trace-env can be
889+
// checked when parsing NODE_DEBUG_NATIVE. It should also be done after
890+
// env_vars() is set so that the parser uses values from env->env_vars()
891+
// which may or may not be the system environment variable store.
892+
enabled_debug_list_.Parse(this);
893+
890894
heap_snapshot_near_heap_limit_ =
891895
static_cast<uint32_t>(options_->heap_snapshot_near_heap_limit);
892896

@@ -1115,8 +1119,7 @@ void Environment::InitializeLibuv() {
11151119

11161120
void Environment::InitializeCompileCache() {
11171121
std::string dir_from_env;
1118-
if (!credentials::SafeGetenv(
1119-
"NODE_COMPILE_CACHE", &dir_from_env, env_vars()) ||
1122+
if (!credentials::SafeGetenv("NODE_COMPILE_CACHE", &dir_from_env, this) ||
11201123
dir_from_env.empty()) {
11211124
return;
11221125
}
@@ -1128,7 +1131,7 @@ CompileCacheEnableResult Environment::EnableCompileCache(
11281131
CompileCacheEnableResult result;
11291132
std::string disable_env;
11301133
if (credentials::SafeGetenv(
1131-
"NODE_DISABLE_COMPILE_CACHE", &disable_env, env_vars())) {
1134+
"NODE_DISABLE_COMPILE_CACHE", &disable_env, this)) {
11321135
result.status = CompileCacheEnableStatus::DISABLED;
11331136
result.message = "Disabled by NODE_DISABLE_COMPILE_CACHE";
11341137
Debug(this,
Collapse file

‎src/node.cc‎

Copy file name to clipboardExpand all lines: src/node.cc
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1045,7 +1045,7 @@ InitializeOncePerProcessInternal(const std::vector<std::string>& args,
10451045
if (!(flags & ProcessInitializationFlags::kNoParseGlobalDebugVariables)) {
10461046
// Initialized the enabled list for Debug() calls with system
10471047
// environment variables.
1048-
per_process::enabled_debug_list.Parse(per_process::system_environment);
1048+
per_process::enabled_debug_list.Parse(nullptr);
10491049
}
10501050

10511051
PlatformInit(flags);
Collapse file

‎src/node_credentials.cc‎

Copy file name to clipboardExpand all lines: src/node_credentials.cc
+24-9Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,7 @@ static bool HasOnly(int capability) {
7272
// process only has the capability CAP_NET_BIND_SERVICE set. If the current
7373
// process does not have any capabilities set and the process is running as
7474
// setuid root then lookup will not be allowed.
75-
bool SafeGetenv(const char* key,
76-
std::string* text,
77-
std::shared_ptr<KVStore> env_vars) {
75+
bool SafeGetenv(const char* key, std::string* text, Environment* env) {
7876
#if !defined(__CloudABI__) && !defined(_WIN32)
7977
#if defined(__linux__)
8078
if ((!HasOnly(CAP_NET_BIND_SERVICE) && linux_at_secure()) ||
@@ -87,14 +85,31 @@ bool SafeGetenv(const char* key,
8785

8886
// Fallback to system environment which reads the real environment variable
8987
// through uv_os_getenv.
90-
if (env_vars == nullptr) {
88+
std::shared_ptr<KVStore> env_vars;
89+
if (env == nullptr) {
9190
env_vars = per_process::system_environment;
91+
} else {
92+
env_vars = env->env_vars();
9293
}
9394

9495
std::optional<std::string> value = env_vars->Get(key);
95-
if (!value.has_value()) return false;
96-
*text = value.value();
97-
return true;
96+
97+
bool has_env = value.has_value();
98+
if (has_env) {
99+
*text = value.value();
100+
}
101+
102+
auto options =
103+
(env != nullptr ? env->options()
104+
: per_process::cli_options->per_isolate->per_env);
105+
106+
if (options->trace_env) {
107+
fprintf(stderr, "[--trace-env] get environment variable \"%s\"\n", key);
108+
109+
PrintTraceEnvStack(options);
110+
}
111+
112+
return has_env;
98113
}
99114

100115
static void SafeGetenv(const FunctionCallbackInfo<Value>& args) {
@@ -103,7 +118,7 @@ static void SafeGetenv(const FunctionCallbackInfo<Value>& args) {
103118
Isolate* isolate = env->isolate();
104119
Utf8Value strenvtag(isolate, args[0]);
105120
std::string text;
106-
if (!SafeGetenv(*strenvtag, &text, env->env_vars())) return;
121+
if (!SafeGetenv(*strenvtag, &text, env)) return;
107122
Local<Value> result =
108123
ToV8Value(isolate->GetCurrentContext(), text).ToLocalChecked();
109124
args.GetReturnValue().Set(result);
@@ -117,7 +132,7 @@ static void GetTempDir(const FunctionCallbackInfo<Value>& args) {
117132

118133
// Let's wrap SafeGetEnv since it returns true for empty string.
119134
auto get_env = [&dir, &env](std::string_view key) {
120-
USE(SafeGetenv(key.data(), &dir, env->env_vars()));
135+
USE(SafeGetenv(key.data(), &dir, env));
121136
return !dir.empty();
122137
};
123138

Collapse file

‎src/node_env_var.cc‎

Copy file name to clipboardExpand all lines: src/node_env_var.cc
+60-2Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,19 @@ Maybe<void> KVStore::AssignToObject(v8::Isolate* isolate,
337337
return JustVoid();
338338
}
339339

340+
void PrintTraceEnvStack(Environment* env) {
341+
PrintTraceEnvStack(env->options());
342+
}
343+
344+
void PrintTraceEnvStack(std::shared_ptr<EnvironmentOptions> options) {
345+
if (options->trace_env_native_stack) {
346+
DumpNativeBacktrace(stderr);
347+
}
348+
if (options->trace_env_js_stack) {
349+
DumpJavaScriptBacktrace(stderr);
350+
}
351+
}
352+
340353
static Intercepted EnvGetter(Local<Name> property,
341354
const PropertyCallbackInfo<Value>& info) {
342355
Environment* env = Environment::GetCurrent(info);
@@ -348,7 +361,18 @@ static Intercepted EnvGetter(Local<Name> property,
348361
CHECK(property->IsString());
349362
MaybeLocal<String> value_string =
350363
env->env_vars()->Get(env->isolate(), property.As<String>());
351-
if (!value_string.IsEmpty()) {
364+
365+
bool has_env = !value_string.IsEmpty();
366+
if (env->options()->trace_env) {
367+
Utf8Value key(env->isolate(), property.As<String>());
368+
fprintf(stderr,
369+
"[--trace-env] get environment variable \"%.*s\"\n",
370+
static_cast<int>(key.length()),
371+
key.out());
372+
PrintTraceEnvStack(env);
373+
}
374+
375+
if (has_env) {
352376
info.GetReturnValue().Set(value_string.ToLocalChecked());
353377
return Intercepted::kYes;
354378
}
@@ -386,6 +410,14 @@ static Intercepted EnvSetter(Local<Name> property,
386410
}
387411

388412
env->env_vars()->Set(env->isolate(), key, value_string);
413+
if (env->options()->trace_env) {
414+
Utf8Value key_utf8(env->isolate(), key);
415+
fprintf(stderr,
416+
"[--trace-env] set environment variable \"%.*s\"\n",
417+
static_cast<int>(key_utf8.length()),
418+
key_utf8.out());
419+
PrintTraceEnvStack(env);
420+
}
389421

390422
return Intercepted::kYes;
391423
}
@@ -396,7 +428,18 @@ static Intercepted EnvQuery(Local<Name> property,
396428
CHECK(env->has_run_bootstrapping_code());
397429
if (property->IsString()) {
398430
int32_t rc = env->env_vars()->Query(env->isolate(), property.As<String>());
399-
if (rc != -1) {
431+
bool has_env = (rc != -1);
432+
433+
if (env->options()->trace_env) {
434+
Utf8Value key_utf8(env->isolate(), property.As<String>());
435+
fprintf(stderr,
436+
"[--trace-env] query environment variable \"%.*s\": %s\n",
437+
static_cast<int>(key_utf8.length()),
438+
key_utf8.out(),
439+
has_env ? "is set" : "is not set");
440+
PrintTraceEnvStack(env);
441+
}
442+
if (has_env) {
400443
// Return attributes for the property.
401444
info.GetReturnValue().Set(v8::None);
402445
return Intercepted::kYes;
@@ -411,6 +454,15 @@ static Intercepted EnvDeleter(Local<Name> property,
411454
CHECK(env->has_run_bootstrapping_code());
412455
if (property->IsString()) {
413456
env->env_vars()->Delete(env->isolate(), property.As<String>());
457+
458+
if (env->options()->trace_env) {
459+
Utf8Value key_utf8(env->isolate(), property.As<String>());
460+
fprintf(stderr,
461+
"[--trace-env] delete environment variable \"%.*s\"\n",
462+
static_cast<int>(key_utf8.length()),
463+
key_utf8.out());
464+
PrintTraceEnvStack(env);
465+
}
414466
}
415467

416468
// process.env never has non-configurable properties, so always
@@ -423,6 +475,12 @@ static void EnvEnumerator(const PropertyCallbackInfo<Array>& info) {
423475
Environment* env = Environment::GetCurrent(info);
424476
CHECK(env->has_run_bootstrapping_code());
425477

478+
if (env->options()->trace_env) {
479+
fprintf(stderr, "[--trace-env] enumerate environment variables\n");
480+
481+
PrintTraceEnvStack(env);
482+
}
483+
426484
info.GetReturnValue().Set(
427485
env->env_vars()->Enumerate(env->isolate()));
428486
}
Collapse file

‎src/node_internals.h‎

Copy file name to clipboardExpand all lines: src/node_internals.h
+4-3Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,11 +321,12 @@ class ThreadPoolWork {
321321
#endif // defined(__POSIX__) && !defined(__ANDROID__) && !defined(__CloudABI__)
322322

323323
namespace credentials {
324-
bool SafeGetenv(const char* key,
325-
std::string* text,
326-
std::shared_ptr<KVStore> env_vars = nullptr);
324+
bool SafeGetenv(const char* key, std::string* text, Environment* env = nullptr);
327325
} // namespace credentials
328326

327+
void PrintTraceEnvStack(Environment* env);
328+
void PrintTraceEnvStack(std::shared_ptr<EnvironmentOptions> options);
329+
329330
void DefineZlibConstants(v8::Local<v8::Object> target);
330331
v8::Isolate* NewIsolate(v8::Isolate::CreateParams* params,
331332
uv_loop_t* event_loop,
Collapse file

‎src/node_options.cc‎

Copy file name to clipboardExpand all lines: src/node_options.cc
+18Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,24 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() {
775775
"show stack traces on promise initialization and resolution",
776776
&EnvironmentOptions::trace_promises,
777777
kAllowedInEnvvar);
778+
779+
AddOption("--trace-env",
780+
"Print accesses to the environment variables",
781+
&EnvironmentOptions::trace_env,
782+
kAllowedInEnvvar);
783+
Implies("--trace-env-js-stack", "--trace-env");
784+
Implies("--trace-env-native-stack", "--trace-env");
785+
AddOption("--trace-env-js-stack",
786+
"Print accesses to the environment variables and the JavaScript "
787+
"stack trace",
788+
&EnvironmentOptions::trace_env_js_stack,
789+
kAllowedInEnvvar);
790+
AddOption(
791+
"--trace-env-native-stack",
792+
"Print accesses to the environment variables and the native stack trace",
793+
&EnvironmentOptions::trace_env_native_stack,
794+
kAllowedInEnvvar);
795+
778796
AddOption("--experimental-default-type",
779797
"set module system to use by default",
780798
&EnvironmentOptions::type,
Collapse file

‎src/node_options.h‎

Copy file name to clipboardExpand all lines: src/node_options.h
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ class EnvironmentOptions : public Options {
210210
bool trace_uncaught = false;
211211
bool trace_warnings = false;
212212
bool trace_promises = false;
213+
bool trace_env = false;
214+
bool trace_env_js_stack = false;
215+
bool trace_env_native_stack = false;
213216
bool extra_info_on_fatal_exception = true;
214217
std::string unhandled_rejections;
215218
std::vector<std::string> userland_loaders;

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.