https://github.com/python/cpython/commit/bf397e272c2bee639c3ba0208c221f7dd9447bb6
commit: bf397e272c2bee639c3ba0208c221f7dd9447bb6
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: kumaraditya303 <[email protected]>
date: 2025-10-07T18:18:23Z
summary:

[3.14] gh-133467: fix data race in `type_set_name` (GH-137302) (#137303)

gh-133467: fix data race in `type_set_name` (GH-137302)

Fix data race in `type_set_name` by assigning name under stop the world pause 
making it thread safe in free-threading.
(cherry picked from commit e99bc7fd44bbbf2464c37d5a57777ac0e1264c37)

Co-authored-by: Kumar Aditya <[email protected]>

files:
M Lib/test/test_free_threading/test_type.py
M Objects/typeobject.c
M Tools/tsan/suppressions_free_threading.txt

diff --git a/Lib/test/test_free_threading/test_type.py 
b/Lib/test/test_free_threading/test_type.py
index ae996e7db3c7fd..2d995751005d71 100644
--- a/Lib/test/test_free_threading/test_type.py
+++ b/Lib/test/test_free_threading/test_type.py
@@ -127,6 +127,20 @@ class ClassB(Base):
         obj.__class__ = ClassB
 
 
+    def test_name_change(self):
+        class Foo:
+            pass
+
+        def writer():
+            for _ in range(1000):
+                Foo.__name__ = 'Bar'
+
+        def reader():
+            for _ in range(1000):
+                Foo.__name__
+
+        self.run_one(writer, reader)
+
     def run_one(self, writer_func, reader_func):
         barrier = threading.Barrier(NTHREADS)
 
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 06b4998507ce9f..28451fee7ec10f 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1434,9 +1434,13 @@ type_set_name(PyObject *tp, PyObject *value, void 
*Py_UNUSED(closure))
         return -1;
     }
 
+    PyInterpreterState *interp = _PyInterpreterState_GET();
+    _PyEval_StopTheWorld(interp);
     type->tp_name = tp_name;
-    Py_SETREF(((PyHeapTypeObject*)type)->ht_name, Py_NewRef(value));
-
+    PyObject *old_name = ((PyHeapTypeObject*)type)->ht_name;
+    ((PyHeapTypeObject*)type)->ht_name = Py_NewRef(value);
+    _PyEval_StartTheWorld(interp);
+    Py_DECREF(old_name);
     return 0;
 }
 
@@ -10406,9 +10410,11 @@ slot_tp_descr_get(PyObject *self, PyObject *obj, 
PyObject *type)
 
     get = _PyType_LookupRef(tp, &_Py_ID(__get__));
     if (get == NULL) {
+#ifndef Py_GIL_DISABLED
         /* Avoid further slowdowns */
         if (tp->tp_descr_get == slot_tp_descr_get)
             tp->tp_descr_get = NULL;
+#endif
         return Py_NewRef(self);
     }
     if (obj == NULL)
diff --git a/Tools/tsan/suppressions_free_threading.txt 
b/Tools/tsan/suppressions_free_threading.txt
index 580757ddd75033..c10af91faae17c 100644
--- a/Tools/tsan/suppressions_free_threading.txt
+++ b/Tools/tsan/suppressions_free_threading.txt
@@ -50,7 +50,5 @@ race:PyObject_Realloc
 
 # gh-133467.  Some of these could be hard to trigger.
 race_top:update_one_slot
-race_top:slot_tp_descr_get
-race_top:type_set_name
 race_top:set_tp_bases
 race_top:type_set_bases_unlocked

_______________________________________________
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