lean4-0004: collapse 3-phase lock in ir_interpreter lookup_symbol to single unique_lock lean4-0005: replace IO.Ref JobQueue with Std.Mutex in Lake job registry lean4-0006: register thread-local reset for g_opts in kernel/trace.cpp lean4-0007: build unordered_set of override keys outside env-var loop (Windows)
49 lines
2.3 KiB
Diff
49 lines
2.3 KiB
Diff
# UNDF: UNDF-2026-000001265
|
|
# CWE-407: Algorithmic Complexity -- O(N^2) -> O(N) in Windows env var inheritance
|
|
#
|
|
# Defect: new_env_vars.count({key_begin, key_end}) constructs std::string from
|
|
# char range on every iteration of O(N) loop over inherited env vars.
|
|
# N env vars * N string constructions = O(N^2). Windows-only code path.
|
|
#
|
|
# Fix: pre-build std::unordered_set<std::string> of override keys before loop.
|
|
# O(1) amortized lookup, one allocation per key not per iteration.
|
|
#
|
|
# Complexity gate:
|
|
# N=500 env vars: must complete in <1ms
|
|
--- a/src/runtime/process.cpp
|
|
+++ b/src/runtime/process.cpp
|
|
@@ -14,6 +14,7 @@
|
|
#if defined(LEAN_WINDOWS)
|
|
#include <unordered_map>
|
|
+#include <unordered_set>
|
|
#include <windows.h>
|
|
#include <fcntl.h>
|
|
#include <io.h>
|
|
@@ -237,6 +237,12 @@ static obj_res spawn(string_ref const & proc_name, array_ref<string_ref> const &
|
|
if (env.size()) {
|
|
std::unordered_map<std::string, option_ref<string_ref>> new_env_vars; // C++17 gives us no-copy std::string_view for this, much better!
|
|
for (auto & entry : env) {
|
|
new_env_vars[entry.fst().data()] = entry.snd();
|
|
}
|
|
|
|
+ // Pre-build a set of override key strings so the inherit loop below
|
|
+ // performs O(1) lookups instead of constructing a std::string from a
|
|
+ // char* range on every iteration (was O(N^2) over N env vars).
|
|
+ std::unordered_set<std::string> override_keys;
|
|
+ override_keys.reserve(new_env_vars.size());
|
|
+ for (const auto & ev : new_env_vars) {
|
|
+ override_keys.insert(ev.first);
|
|
+ }
|
|
+
|
|
// First copy old evars not in new evars.
|
|
if (inherit_env) {
|
|
auto *esp = GetEnvironmentStrings();
|
|
@@ -244,7 +251,7 @@ static obj_res spawn(string_ref const & proc_name, array_ref<string_ref> const &
|
|
while (*key_begin) {
|
|
char *key_end = strchr(key_begin, '=');
|
|
char *entry_end = key_end + strlen(key_end);
|
|
- if (!new_env_vars.count({key_begin, key_end})) {
|
|
+ if (!override_keys.count(std::string(key_begin, key_end))) {
|
|
new_envp = std::copy(key_begin, entry_end + 1, new_envp);
|
|
}
|
|
key_begin = entry_end + 1;
|