# UNDF: UNDF-2026-000000675 # UNDF: (pending) # cpython-0004: idlelib.rpc._getmethods — O(2^D) diamond base traversal ## CWE-407 — Algorithmic Complexity: O(2^D) diamond mixin/base traversal | Field | Value | |-------|-------| | ID | cpython-0004 | | Severity | MEDIUM | | Ecosystem | cpython | | Package | idlelib.rpc | | File | `Lib/idlelib/rpc.py` | | Lines | 581–590 | | Complexity | O(2^D) on diamond inheritance hierarchies | | Hot path | Triggered when IDLE debugger calls `__methods__` on a remote object (every debug session inspect) | ## Defect ```python # BEFORE (DEFECT) — O(2^D): no visited guard, unconditional recursion into __bases__ def _getmethods(obj, methods): # Helper to get a list of methods from an object # Adds names to dictionary argument 'methods' for name in dir(obj): attr = getattr(obj, name) if callable(attr): methods[name] = 1 if isinstance(obj, type): for super in obj.__bases__: _getmethods(super, methods) # unconditional — diamond re-traversal ``` Called via IDLE RPC when someone requests `__methods__` (line 179–181): ```python if methodname == "__methods__": methods = {} _getmethods(obj, methods) ``` With a diamond hierarchy, each shared ancestor is visited 2^D times instead of once. `dir(obj)` is called on each visit, making the actual cost O(2^D × M) where M is the number of methods per class. ## Fix ```python # AFTER — O(N): pass visited set to prevent re-traversal of shared ancestors def _getmethods(obj, methods, _visited=None): if _visited is None: _visited = set() if obj in _visited: return _visited.add(obj) for name in dir(obj): attr = getattr(obj, name) if callable(attr): methods[name] = 1 if isinstance(obj, type): for super in obj.__bases__: _getmethods(super, methods, _visited) ``` ## Speedup | Diamond depth (D) | `dir()` calls (before) | `dir()` calls (after) | Speedup | |------------------|----------------------|----------------------|---------| | 5 | 31 | 6 | 5× | | 10 | 1,023 | 11 | 93× | | 15 | 32,767 | 16 | 2,048× | ## Notes `dir()` is an expensive call (it consults `__dict__`, `__dir__`, and all descriptor slots). In a deep diamond hierarchy under the IDLE debugger, inspecting a complex object could cause the IDLE UI to stall for seconds. The `methods` dict deduplication only prevents incorrect output — it does not prevent the exponential traversal cost.