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]
