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

Fix data race in `type_set_name` by assigning name under stop the world pause making it thread safe in free-threading.
This commit is contained in:
Kumar Aditya 2025-08-01 19:10:40 +05:30 committed by GitHub
parent 9ced5c4ace
commit e99bc7fd44
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 22 additions and 4 deletions

View file

@ -127,6 +127,20 @@ class ClassB(Base):
obj.__class__ = ClassB 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): def run_one(self, writer_func, reader_func):
barrier = threading.Barrier(NTHREADS) barrier = threading.Barrier(NTHREADS)

View file

@ -1535,9 +1535,13 @@ type_set_name(PyObject *tp, PyObject *value, void *Py_UNUSED(closure))
return -1; return -1;
} }
PyInterpreterState *interp = _PyInterpreterState_GET();
_PyEval_StopTheWorld(interp);
type->tp_name = tp_name; 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; return 0;
} }
@ -10706,9 +10710,11 @@ slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type)
get = _PyType_LookupRef(tp, &_Py_ID(__get__)); get = _PyType_LookupRef(tp, &_Py_ID(__get__));
if (get == NULL) { if (get == NULL) {
#ifndef Py_GIL_DISABLED
/* Avoid further slowdowns */ /* Avoid further slowdowns */
if (tp->tp_descr_get == slot_tp_descr_get) if (tp->tp_descr_get == slot_tp_descr_get)
tp->tp_descr_get = NULL; tp->tp_descr_get = NULL;
#endif
return Py_NewRef(self); return Py_NewRef(self);
} }
if (obj == NULL) if (obj == NULL)

View file

@ -44,7 +44,5 @@ race:PyObject_Realloc
# gh-133467. Some of these could be hard to trigger. # gh-133467. Some of these could be hard to trigger.
race_top:_Py_slot_tp_getattr_hook 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:set_tp_bases
race_top:type_set_bases_unlocked race_top:type_set_bases_unlocked