40 lines
1.9 KiB
Diff
40 lines
1.9 KiB
Diff
# UNDF: UNDF-2026-000000235
|
|
Fixes pyramid-0005: registry.py Introspector.relate()/unrelate() — list-backed relationship tracking with O(n) membership and removal.
|
|
|
|
--- a/src/pyramid/registry.py
|
|
+++ b/src/pyramid/registry.py
|
|
|
|
@@ DEFECT pyramid-0005: Introspector.relate()/unrelate() lines 185-199
|
|
|
|
class Introspector:
|
|
def __init__(self):
|
|
self._categories = {}
|
|
- self._refs = {} # introspectable → list of related — CWE-407
|
|
+ self._refs = {} # introspectable → list of related (preserved for related())
|
|
+ self._refs_set = {} # FIX pyramid-0005: introspectable → set for O(1) ops
|
|
|
|
def relate(self, *pairs):
|
|
introspectables = self._get_intrs_by_pairs(pairs)
|
|
relatable = ((x, y) for x in introspectables for y in introspectables)
|
|
for x, y in relatable:
|
|
L = self._refs.setdefault(x, [])
|
|
- if x is not y and y not in L: # O(n) list scan — CWE-407
|
|
+ S = self._refs_set.setdefault(x, set())
|
|
+ if x is not y and y not in S: # O(1) set lookup — fixed
|
|
L.append(y)
|
|
+ S.add(y)
|
|
|
|
def unrelate(self, *pairs):
|
|
introspectables = self._get_intrs_by_pairs(pairs)
|
|
relatable = ((x, y) for x in introspectables for y in introspectables)
|
|
for x, y in relatable:
|
|
L = self._refs.get(x, [])
|
|
- if y in L: # O(n) list scan — CWE-407
|
|
- L.remove(y) # O(n) list removal — CWE-407
|
|
+ S = self._refs_set.get(x, set())
|
|
+ if y in S: # O(1) set lookup — fixed
|
|
+ L.remove(y) # O(n) but confirmed; one call per unrelate
|
|
+ S.discard(y)
|
|
|
|
# NOTE: _refs list is kept for related() return value (callers may rely on list type).
|
|
# _refs_set shadow provides O(1) dedup in relate() and O(1) guard in unrelate().
|