Skip to content

Commit 0df5ffa

Browse files
committed
fix PyTypeObject->tp_base race in free threading
1 parent 95e5d59 commit 0df5ffa

File tree

3 files changed

+26
-0
lines changed

3 files changed

+26
-0
lines changed

Lib/test/test_free_threading/test_type.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,25 @@ def reader():
141141

142142
self.run_one(writer, reader)
143143

144+
def test_bases_change(self):
145+
class BaseA:
146+
pass
147+
148+
class Derived(BaseA):
149+
pass
150+
151+
def writer():
152+
for _ in range(1000):
153+
class BaseB:
154+
pass
155+
Derived.__bases__ = (BaseB,)
156+
157+
def reader():
158+
for _ in range(1000):
159+
Derived.__base__
160+
161+
self.run_one(writer, reader)
162+
144163
def run_one(self, writer_func, reader_func):
145164
barrier = threading.Barrier(NTHREADS)
146165

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix race when updating ``type.__bases__`` that could allow a read of ``type.__base__`` to observe an inconsistent value on the free threaded build.

Objects/typeobject.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,7 +1921,11 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, PyTypeObject *b
19211921
PyTypeObject *old_base = type->tp_base;
19221922

19231923
set_tp_bases(type, Py_NewRef(new_bases), 0);
1924+
1925+
PyInterpreterState *interp = _PyInterpreterState_GET();
1926+
_PyEval_StopTheWorld(interp);
19241927
type->tp_base = (PyTypeObject *)Py_NewRef(best_base);
1928+
_PyEval_StartTheWorld(interp);
19251929

19261930
PyObject *temp = PyList_New(0);
19271931
if (temp == NULL) {
@@ -1983,7 +1987,9 @@ type_set_bases_unlocked(PyTypeObject *type, PyObject *new_bases, PyTypeObject *b
19831987
assert(type->tp_base == best_base);
19841988

19851989
set_tp_bases(type, old_bases, 0);
1990+
_PyEval_StopTheWorld(interp);
19861991
type->tp_base = old_base;
1992+
_PyEval_StartTheWorld(interp);
19871993

19881994
Py_DECREF(new_bases);
19891995
Py_DECREF(best_base);

0 commit comments

Comments
 (0)