45 lines
2.1 KiB
Diff
45 lines
2.1 KiB
Diff
# UNDF: UNDF-2026-000000182
|
||
From: agent-blackops <blackops@unturf.com>
|
||
Date: Thu, 26 Mar 2026 00:00:00 +0000
|
||
Subject: [PATCH] algorithms/cycles: replace B defaultdict(list) with defaultdict(set) in recursive_simple_cycles
|
||
|
||
CWE-407: Algorithmic complexity via O(N) list membership test in
|
||
recursive_simple_cycles(). B was a defaultdict(list) used to track
|
||
graph portions yielding no elementary circuit. The inner loop called
|
||
`if thisnode not in B[nextnode]` (O(|B[nextnode]|)) followed by
|
||
`B[nextnode].append(thisnode)` inside circuit(), which is invoked for
|
||
every edge in every DFS frame. Total cost per component is O(E × |B|).
|
||
|
||
Replace with defaultdict(set): `not in` on a set is O(1) amortised;
|
||
`add` replaces `append`. The `_unblock` helper uses `pop()` on the
|
||
collection — set.pop() is valid and semantically equivalent here since
|
||
order does not matter for unblocking. No algorithmic contract changes.
|
||
|
||
Defect-Id: NX-001
|
||
Severity: MEDIUM
|
||
CWE: CWE-407 (Inefficient Algorithmic Complexity)
|
||
---
|
||
networkx/algorithms/cycles.py | 6 +++---
|
||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||
|
||
diff --git a/networkx/algorithms/cycles.py b/networkx/algorithms/cycles.py
|
||
index xxxxxxx..yyyyyyy 100644
|
||
--- a/networkx/algorithms/cycles.py
|
||
+++ b/networkx/algorithms/cycles.py
|
||
@@ -840,11 +840,11 @@ def recursive_simple_cycles(G):
|
||
if closed:
|
||
_unblock(thisnode)
|
||
else:
|
||
for nextnode in component[thisnode]:
|
||
- if thisnode not in B[nextnode]: # TODO: use set for speedup?
|
||
- B[nextnode].append(thisnode)
|
||
+ if thisnode not in B[nextnode]: # CWE-407 fix: O(1) set lookup
|
||
+ B[nextnode].add(thisnode) # CWE-407 fix: O(1) set insert
|
||
path.pop() # remove thisnode from path
|
||
return closed
|
||
|
||
path = [] # stack of nodes in current path
|
||
blocked = defaultdict(bool) # vertex: blocked from search?
|
||
- B = defaultdict(list) # graph portions that yield no elementary circuit
|
||
+ B = defaultdict(set) # CWE-407 fix: set for O(1) membership and insert
|
||
result = [] # list to accumulate the circuits found
|