TypeAliasType's traverse implementation does not visit its name. This means that we can leak memory if name is passed an instance of a mutable str subclass.
from typing import TypeAliasType import weakref import gc class S(str): pass def still_alive(ref): obj = ref() if not isinstance(obj, S): return False T = obj.T if not isinstance(T, TypeAliasType): return False return T name = S("name") T = TypeAliasType(name, int) name.T = T ref = weakref.ref(name) assert still_alive(ref) del name del T gc.collect() gc.collect() assert still_alive(ref) del ref().T assert not still_alive(ref)
CPython main branch
macOS
This also affects TypeVar, TypeVarTuple, and ParamSpec.
Leak for all 4 types is confirmed on main, 3.14 and 3.13 branches. PR with fix is submitted.
gh-140000: Traverse `name` attribute for `TypeVar`, `TypeVarTuple`, `…
pythongh-140000: Traverse `name` attribute for `TypeVar`, `TypeVarTup…
[3.14] gh-140000: Traverse `name` attribute for `TypeVar`, `TypeVarTu…
[3.13] gh-140000: Traverse `name` attribute for `TypeVar`, `TypeVarTu…
Activity
JelleZijlstra commented on Oct 12, 2025
This also affects TypeVar, TypeVarTuple, and ParamSpec.
efimov-mikhail commented on Oct 12, 2025
Leak for all 4 types is confirmed on main, 3.14 and 3.13 branches. PR with fix is submitted.
gh-140000: Traverse `name` attribute for `TypeVar`, `TypeVarTuple`, `…
pythongh-140000: Traverse `name` attribute for `TypeVar`, `TypeVarTup…
[3.14] gh-140000: Traverse `name` attribute for `TypeVar`, `TypeVarTu…
[3.13] gh-140000: Traverse `name` attribute for `TypeVar`, `TypeVarTu…