25 lines
1.2 KiB
Diff
25 lines
1.2 KiB
Diff
# UNDF: UNDF-2026-000000159
|
|
diff --git a/luigi/tools/deps.py b/luigi/tools/deps.py
|
|
--- a/luigi/tools/deps.py
|
|
+++ b/luigi/tools/deps.py
|
|
@@ -55,9 +55,14 @@ def get_task_requires(task):
|
|
return set(flatten(task.requires()))
|
|
|
|
|
|
-def dfs_paths(start_task, goal_task_family, path=None):
|
|
+def dfs_paths(start_task, goal_task_family, path=None, path_set=None):
|
|
+ # CWE-407 fix: maintain a parallel set alongside the path list so the
|
|
+ # visited-ancestor check is O(1) instead of rebuilding set(path) — O(depth)
|
|
+ # — on every recursive call. Previously: O(D²) total; now: O(D).
|
|
if path is None:
|
|
path = [start_task]
|
|
- if start_task.task_family == goal_task_family or goal_task_family is None:
|
|
+ path_set = {start_task}
|
|
+ if start_task.task_family == goal_task_family or goal_task_family is None:
|
|
for item in path:
|
|
yield item
|
|
- for next in get_task_requires(start_task) - set(path):
|
|
- for t in dfs_paths(next, goal_task_family, path + [next]):
|
|
+ for next in get_task_requires(start_task) - path_set:
|
|
+ for t in dfs_paths(next, goal_task_family, path + [next], path_set | {next}):
|
|
yield t
|