# UNDF: UNDF-2026-000000674
# UNDF: (pending)
# cpython-0003: turtle.__methodDict — O(2^D) diamond base traversal

## CWE-407 — Algorithmic Complexity: O(2^D) diamond mixin/base traversal

| Field | Value |
|-------|-------|
| ID | cpython-0003 |
| Severity | MEDIUM |
| Ecosystem | cpython |
| Package | turtle |
| File | `Lib/turtle.py` |
| Lines | 286–293 |
| Complexity | O(2^D) on diamond inheritance hierarchies |
| Hot path | Called at module import time via `__forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')` |

## Defect

```python
# BEFORE (DEFECT) — O(2^D): no visited guard, unconditional recursion into __bases__
def __methodDict(cls, _dict):
    """helper function for Scrolled Canvas"""
    baseList = list(cls.__bases__)
    baseList.reverse()
    for _super in baseList:
        __methodDict(_super, _dict)   # unconditional — diamond re-traversal
    for key, value in cls.__dict__.items():
        if type(value) == types.FunctionType:
            _dict[key] = value
```

Called at module import time (line 426):
```python
__forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')
```

`__forwardmethods` calls `__methodDict(toClass, _dict_1)` where `toClass` is `TK.Canvas`.
If `TK.Canvas` participates in a diamond MRO (common in Tkinter/ttk widget hierarchies),
the traversal visits shared ancestors exponentially many times.

## Fix

```python
# AFTER — O(N): pass visited set to prevent re-traversal of shared ancestors
def __methodDict(cls, _dict, _visited=None):
    """helper function for Scrolled Canvas"""
    if _visited is None:
        _visited = set()
    if cls in _visited:
        return
    _visited.add(cls)
    baseList = list(cls.__bases__)
    baseList.reverse()
    for _super in baseList:
        __methodDict(_super, _dict, _visited)
    for key, value in cls.__dict__.items():
        if type(value) == types.FunctionType:
            _dict[key] = value
```

Alternatively, use `cls.__mro__` directly:

```python
# SIMPLER FIX: iterate MRO (linearized, no duplicates)
def __methodDict(cls, _dict):
    """helper function for Scrolled Canvas"""
    for klass in reversed(cls.__mro__):
        for key, value in klass.__dict__.items():
            if type(value) == types.FunctionType:
                _dict[key] = value
```

## Speedup

| Diamond depth (D) | Nodes visited (before) | Nodes visited (after) | Speedup |
|------------------|----------------------|----------------------|---------|
| 5 | 31 | 6 | 5× |
| 10 | 1,023 | 11 | 93× |
| 15 | 32,767 | 16 | 2,048× |

## Notes

This fires at every `import turtle` since `__forwardmethods` is called unconditionally at
module level. For typical Tkinter class hierarchies the depth is bounded, limiting practical
impact — but ttk widgets add multiple inheritance layers that could trigger exponential behavior.
