30 lines
1.2 KiB
Diff
30 lines
1.2 KiB
Diff
# UNDF: UNDF-2026-000000065
|
|
--- a/lib/kernel/src/code_server.erl
|
|
+++ b/lib/kernel/src/code_server.erl
|
|
@@ -598,14 +598,19 @@ merge_path(Path,IPath,Acc) ->
|
|
merge_path1(Path,IPath,Acc).
|
|
|
|
-merge_path1([P|Path],IPath,Acc) ->
|
|
- case lists:member(P,Acc) of
|
|
+%% CWE-407 fix: merge_path1 used a plain list (Acc) as a seen-set.
|
|
+%% lists:member/2 is O(|Acc|); called once per element of Path, total cost
|
|
+%% is O(|Path|²) when all paths are unique. On a system with N library
|
|
+%% directories (common in large OTP/Elixir/Erlang deployments), this
|
|
+%% runs at startup and every code:add_paths/1 call.
|
|
+%% Fix: carry a sets:set() alongside the accumulator list for O(1) membership.
|
|
+merge_path1([P|Path],IPath,Acc) ->
|
|
+ merge_path1([P|Path],IPath,Acc,sets:new()).
|
|
+
|
|
+merge_path1([P|Path],IPath,Acc,Seen) ->
|
|
+ case sets:is_element(P,Seen) of
|
|
true ->
|
|
- merge_path1(Path,IPath,Acc); % Already added
|
|
+ merge_path1(Path,IPath,Acc,Seen); % Already added
|
|
false ->
|
|
IPath1 = exclude(P,IPath),
|
|
- merge_path1(Path,IPath1,[P|Acc])
|
|
+ merge_path1(Path,IPath1,[P|Acc],sets:add_element(P,Seen))
|
|
end;
|
|
-merge_path1(_,IPath,Acc) ->
|
|
+merge_path1(_,IPath,Acc,_Seen) ->
|
|
lists:reverse(Acc) ++ IPath.
|