Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
24 lines
1.1 KiB
Diff
24 lines
1.1 KiB
Diff
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
|