https://github.com/python/cpython/commit/cbcee9a0f018779b7f41436afe62090a0c4405a9
commit: cbcee9a0f018779b7f41436afe62090a0c4405a9
branch: 3.13
author: Mikhail Efimov <[email protected]>
committer: JelleZijlstra <[email protected]>
date: 2025-10-13T20:02:32-07:00
summary:

[3.13] gh-140000: Traverse `name` attribute for `TypeVar`, `TypeVarTuple`, 
`TypeAliasType`, `ParamSpec` (GH-140016) (#140073)

Correct traversing name attribute for TypeVar, TypeVarTuple, TypeAliasType, 
ParamSpec

files:
A Misc/NEWS.d/next/Core and 
Builtins/2025-10-13-17-56-23.gh-issue-140000.tLhn3e.rst
M Objects/typevarobject.c

diff --git a/Misc/NEWS.d/next/Core and 
Builtins/2025-10-13-17-56-23.gh-issue-140000.tLhn3e.rst b/Misc/NEWS.d/next/Core 
and Builtins/2025-10-13-17-56-23.gh-issue-140000.tLhn3e.rst
new file mode 100644
index 00000000000000..2c6259635eaf04
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and 
Builtins/2025-10-13-17-56-23.gh-issue-140000.tLhn3e.rst 
@@ -0,0 +1,4 @@
+Fix potential memory leak when a reference cycle exists between an instance
+of :class:`typing.TypeAliasType`, :class:`typing.TypeVar`,
+:class:`typing.ParamSpec`, or :class:`typing.TypeVarTuple` and its
+``__name__`` attribute. Patch by Mikhail Efimov.
diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c
index f3e3ed0c9afae7..fa6c8d7367d84e 100644
--- a/Objects/typevarobject.c
+++ b/Objects/typevarobject.c
@@ -259,7 +259,7 @@ typevar_dealloc(PyObject *self)
 
     _PyObject_GC_UNTRACK(self);
 
-    Py_DECREF(tv->name);
+    Py_XDECREF(tv->name);
     Py_XDECREF(tv->bound);
     Py_XDECREF(tv->evaluate_bound);
     Py_XDECREF(tv->constraints);
@@ -278,6 +278,7 @@ typevar_traverse(PyObject *self, visitproc visit, void *arg)
 {
     Py_VISIT(Py_TYPE(self));
     typevarobject *tv = (typevarobject *)self;
+    Py_VISIT(tv->name);
     Py_VISIT(tv->bound);
     Py_VISIT(tv->evaluate_bound);
     Py_VISIT(tv->constraints);
@@ -291,6 +292,7 @@ typevar_traverse(PyObject *self, visitproc visit, void *arg)
 static int
 typevar_clear(typevarobject *self)
 {
+    Py_CLEAR(self->name);
     Py_CLEAR(self->bound);
     Py_CLEAR(self->evaluate_bound);
     Py_CLEAR(self->constraints);
@@ -912,7 +914,7 @@ paramspec_dealloc(PyObject *self)
 
     _PyObject_GC_UNTRACK(self);
 
-    Py_DECREF(ps->name);
+    Py_XDECREF(ps->name);
     Py_XDECREF(ps->bound);
     Py_XDECREF(ps->default_value);
     Py_XDECREF(ps->evaluate_default);
@@ -928,6 +930,7 @@ paramspec_traverse(PyObject *self, visitproc visit, void 
*arg)
 {
     Py_VISIT(Py_TYPE(self));
     paramspecobject *ps = (paramspecobject *)self;
+    Py_VISIT(ps->name);
     Py_VISIT(ps->bound);
     Py_VISIT(ps->default_value);
     Py_VISIT(ps->evaluate_default);
@@ -938,6 +941,7 @@ paramspec_traverse(PyObject *self, visitproc visit, void 
*arg)
 static int
 paramspec_clear(paramspecobject *self)
 {
+    Py_CLEAR(self->name);
     Py_CLEAR(self->bound);
     Py_CLEAR(self->default_value);
     Py_CLEAR(self->evaluate_default);
@@ -1244,7 +1248,7 @@ typevartuple_dealloc(PyObject *self)
     _PyObject_GC_UNTRACK(self);
     typevartupleobject *tvt = (typevartupleobject *)self;
 
-    Py_DECREF(tvt->name);
+    Py_XDECREF(tvt->name);
     Py_XDECREF(tvt->default_value);
     Py_XDECREF(tvt->evaluate_default);
     PyObject_ClearManagedDict(self);
@@ -1408,8 +1412,10 @@ static int
 typevartuple_traverse(PyObject *self, visitproc visit, void *arg)
 {
     Py_VISIT(Py_TYPE(self));
-    Py_VISIT(((typevartupleobject *)self)->default_value);
-    Py_VISIT(((typevartupleobject *)self)->evaluate_default);
+    typevartupleobject *tvt = (typevartupleobject *)self;
+    Py_VISIT(tvt->name);
+    Py_VISIT(tvt->default_value);
+    Py_VISIT(tvt->evaluate_default);
     PyObject_VisitManagedDict(self, visit, arg);
     return 0;
 }
@@ -1417,8 +1423,10 @@ typevartuple_traverse(PyObject *self, visitproc visit, 
void *arg)
 static int
 typevartuple_clear(PyObject *self)
 {
-    Py_CLEAR(((typevartupleobject *)self)->default_value);
-    Py_CLEAR(((typevartupleobject *)self)->evaluate_default);
+    typevartupleobject *tvt = (typevartupleobject *)self;
+    Py_CLEAR(tvt->name);
+    Py_CLEAR(tvt->default_value);
+    Py_CLEAR(tvt->evaluate_default);
     PyObject_ClearManagedDict(self);
     return 0;
 }
@@ -1542,7 +1550,7 @@ typealias_dealloc(PyObject *self)
     PyTypeObject *tp = Py_TYPE(self);
     _PyObject_GC_UNTRACK(self);
     typealiasobject *ta = (typealiasobject *)self;
-    Py_DECREF(ta->name);
+    Py_XDECREF(ta->name);
     Py_XDECREF(ta->type_params);
     Py_XDECREF(ta->compute_value);
     Py_XDECREF(ta->value);
@@ -1660,6 +1668,7 @@ typealias_alloc(PyObject *name, PyObject *type_params, 
PyObject *compute_value,
 static int
 typealias_traverse(typealiasobject *self, visitproc visit, void *arg)
 {
+    Py_VISIT(self->name);
     Py_VISIT(self->type_params);
     Py_VISIT(self->compute_value);
     Py_VISIT(self->value);
@@ -1670,6 +1679,7 @@ typealias_traverse(typealiasobject *self, visitproc 
visit, void *arg)
 static int
 typealias_clear(typealiasobject *self)
 {
+    Py_CLEAR(self->name);
     Py_CLEAR(self->type_params);
     Py_CLEAR(self->compute_value);
     Py_CLEAR(self->value);

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to