# 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 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 +#include #include #include #include @@ -237,6 +237,12 @@ static obj_res spawn(string_ref const & proc_name, array_ref const & if (env.size()) { std::unordered_map> 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 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 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;