From a2776fb21953aa3436959784262a04f022bf194e Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Fri, 1 Aug 2025 18:03:57 +0530 Subject: [PATCH 1/4] fix some races --- Lib/test/test_free_threading/test_type.py | 14 ++++++++++++++ Objects/typeobject.c | 6 +++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index ae996e7db3c7fd..12160875007873 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): + self.assertEqual(Foo.__name__, 'Bar') + + 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 d952a58d94af55..15449b19e150f7 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1535,9 +1535,11 @@ 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)); - + _PyEval_StartTheWorld(interp); return 0; } @@ -10706,9 +10708,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) From b12462061462b2ebfe157eaf16683242d32799b4 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Fri, 1 Aug 2025 18:06:39 +0530 Subject: [PATCH 2/4] remove suppressions --- Tools/tsan/suppressions_free_threading.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tools/tsan/suppressions_free_threading.txt b/Tools/tsan/suppressions_free_threading.txt index 93421b623b92f9..52d7c25a5bb37a 100644 --- a/Tools/tsan/suppressions_free_threading.txt +++ b/Tools/tsan/suppressions_free_threading.txt @@ -44,7 +44,5 @@ race:PyObject_Realloc # gh-133467. Some of these could be hard to trigger. race_top:_Py_slot_tp_getattr_hook -race_top:slot_tp_descr_get -race_top:type_set_name race_top:set_tp_bases race_top:type_set_bases_unlocked From dfcd1bf9c75040cd4c0124fd5d74d09cf301c8b8 Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Fri, 1 Aug 2025 18:13:13 +0530 Subject: [PATCH 3/4] decref after starting world --- Objects/typeobject.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 15449b19e150f7..6e67b6e01cb8b8 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1538,8 +1538,10 @@ type_set_name(PyObject *tp, PyObject *value, void *Py_UNUSED(closure)) 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; } From 632f771e5b22260c6e863d1d7588d9afaee497eb Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Fri, 1 Aug 2025 18:43:09 +0530 Subject: [PATCH 4/4] fix test --- Lib/test/test_free_threading/test_type.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index 12160875007873..2d995751005d71 100644 --- a/Lib/test/test_free_threading/test_type.py +++ b/Lib/test/test_free_threading/test_type.py @@ -137,7 +137,7 @@ def writer(): def reader(): for _ in range(1000): - self.assertEqual(Foo.__name__, 'Bar') + Foo.__name__ self.run_one(writer, reader)