Skip to content

Commit 552c021

Browse files
committed
gh-151377: Fix races updating type slots and subclasses in free-threaded builds
1 parent c375992 commit 552c021

1 file changed

Lines changed: 31 additions & 3 deletions

File tree

Objects/typeobject.c

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3943,7 +3943,7 @@ static void object_dealloc(PyObject *);
39433943
static PyObject *object_new(PyTypeObject *, PyObject *, PyObject *);
39443944
static int object_init(PyObject *, PyObject *, PyObject *);
39453945
static int update_slot(PyTypeObject *, PyObject *, slot_update_t *update);
3946-
static void fixup_slot_dispatchers(PyTypeObject *);
3946+
static int fixup_slot_dispatchers(PyTypeObject *);
39473947
static int type_new_set_names(PyTypeObject *);
39483948
static int type_new_init_subclass(PyTypeObject *, PyObject *);
39493949
static bool has_slotdef(PyObject *);
@@ -4954,7 +4954,9 @@ type_new_impl(type_new_ctx *ctx)
49544954
}
49554955

49564956
// Put the proper slots in place
4957-
fixup_slot_dispatchers(type);
4957+
if (fixup_slot_dispatchers(type) < 0) {
4958+
goto error;
4959+
}
49584960

49594961
if (!_PyDict_HasOnlyStringKeys(type->tp_dict)) {
49604962
if (PyErr_WarnFormat(
@@ -6841,7 +6843,13 @@ type_dealloc_common(PyTypeObject *type)
68416843
PyObject *bases = lookup_tp_bases(type);
68426844
if (bases != NULL) {
68436845
PyObject *exc = PyErr_GetRaisedException();
6846+
#ifdef Py_GIL_DISABLED
6847+
BEGIN_TYPE_LOCK();
6848+
#endif
68446849
remove_all_subclasses(type, bases);
6850+
#ifdef Py_GIL_DISABLED
6851+
END_TYPE_LOCK();
6852+
#endif
68456853
PyErr_SetRaisedException(exc);
68466854
}
68476855
}
@@ -12117,13 +12125,33 @@ update_slot(PyTypeObject *type, PyObject *name, slot_update_t *queued_updates)
1211712125
/* Store the proper functions in the slot dispatches at class (type)
1211812126
definition time, based upon which operations the class overrides in its
1211912127
dict. */
12120-
static void
12128+
static int
1212112129
fixup_slot_dispatchers(PyTypeObject *type)
1212212130
{
1212312131
assert(!PyErr_Occurred());
12132+
#ifdef Py_GIL_DISABLED
12133+
slot_update_t queued_updates = {0};
12134+
int res = 0;
12135+
BEGIN_TYPE_LOCK();
12136+
for (pytype_slotdef *p = slotdefs; p->name; ) {
12137+
if (update_one_slot(type, p, &p, &queued_updates) < 0) {
12138+
res = -1;
12139+
break;
12140+
}
12141+
}
12142+
if (res == 0 && queued_updates.head != NULL) {
12143+
apply_type_slot_updates(&queued_updates);
12144+
ASSERT_TYPE_LOCK_HELD();
12145+
}
12146+
END_TYPE_LOCK();
12147+
slot_update_free_chunks(&queued_updates);
12148+
return res;
12149+
#else
1212412150
for (pytype_slotdef *p = slotdefs; p->name; ) {
1212512151
update_one_slot(type, p, &p, NULL);
1212612152
}
12153+
return 0;
12154+
#endif
1212712155
}
1212812156

1212912157
#ifdef Py_GIL_DISABLED

0 commit comments

Comments
 (0)