gh-133467: Fix typeobject tp_base race in free threading (gh-140549)

This commit is contained in:
Edward Xu
2025-11-06 05:20:40 +08:00
committed by GitHub
parent 986bb0a1a2
commit b83f379a97
4 changed files with 30 additions and 4 deletions

View File

@@ -141,6 +141,25 @@ class TestType(TestCase):
self.run_one(writer, reader)
def test_bases_change(self):
class BaseA:
pass
class Derived(BaseA):
pass
def writer():
for _ in range(1000):
class BaseB:
pass
Derived.__bases__ = (BaseB,)
def reader():
for _ in range(1000):
Derived.__base__
self.run_one(writer, reader)
def run_one(self, writer_func, reader_func):
barrier = threading.Barrier(NTHREADS)

View File

@@ -0,0 +1 @@
Fix race when updating :attr:`!type.__bases__` that could allow a read of :attr:`!type.__base__` to observe an inconsistent value on the free threaded build.

View File

@@ -189,6 +189,8 @@ type_lock_allow_release(void)
#define types_world_is_stopped() 1
#define types_stop_world()
#define types_start_world()
#define type_lock_prevent_release()
#define type_lock_allow_release()
#endif
@@ -1920,8 +1922,12 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, PyTypeObject *b
assert(old_bases != NULL);
PyTypeObject *old_base = type->tp_base;
type_lock_prevent_release();
types_stop_world();
set_tp_bases(type, Py_NewRef(new_bases), 0);
type->tp_base = (PyTypeObject *)Py_NewRef(best_base);
types_start_world();
type_lock_allow_release();
PyObject *temp = PyList_New(0);
if (temp == NULL) {
@@ -1982,8 +1988,12 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, PyTypeObject *b
if (lookup_tp_bases(type) == new_bases) {
assert(type->tp_base == best_base);
type_lock_prevent_release();
types_stop_world();
set_tp_bases(type, old_bases, 0);
type->tp_base = old_base;
types_start_world();
type_lock_allow_release();
Py_DECREF(new_bases);
Py_DECREF(best_base);

View File

@@ -41,7 +41,3 @@ race:list_inplace_repeat_lock_held
# PyObject_Realloc internally does memcpy which isn't atomic so can race
# with non-locking reads. See #132070
race:PyObject_Realloc
# gh-133467. Some of these could be hard to trigger.
race_top:set_tp_bases
race_top:type_set_bases_unlocked