bpo-46417: Fix race condition on setting type __bases__ (GH-30788) · python/cpython@f1c6ae3

File tree

2 files changed

lines changed

  • Misc/NEWS.d/next/Core and Builtins

2 files changed

lines changed

Original file line numberDiff line numberDiff line change

@@ -0,0 +1,5 @@

1+

Fix a race condition on setting a type ``__bases__`` attribute: the internal

2+

function ``add_subclass()`` now gets the ``PyTypeObject.tp_subclasses``

3+

member after calling :c:func:`PyWeakref_NewRef` which can trigger a garbage

4+

collection which can indirectly modify ``PyTypeObject.tp_subclasses``. Patch

5+

by Victor Stinner.

Original file line numberDiff line numberDiff line change

@@ -6503,24 +6503,29 @@ PyType_Ready(PyTypeObject *type)

65036503

static int

65046504

add_subclass(PyTypeObject *base, PyTypeObject *type)

65056505

{

6506-

int result = -1;

6507-

PyObject *dict, *key, *newobj;

6506+

PyObject *key = PyLong_FromVoidPtr((void *) type);

6507+

if (key == NULL)

6508+

return -1;

65086509
6509-

dict = base->tp_subclasses;

6510+

PyObject *ref = PyWeakref_NewRef((PyObject *)type, NULL);

6511+

if (ref == NULL) {

6512+

Py_DECREF(key);

6513+

return -1;

6514+

}

6515+
6516+

// Only get tp_subclasses after creating the key and value.

6517+

// PyWeakref_NewRef() can trigger a garbage collection which can execute

6518+

// arbitrary Python code and so modify base->tp_subclasses.

6519+

PyObject *dict = base->tp_subclasses;

65106520

if (dict == NULL) {

65116521

base->tp_subclasses = dict = PyDict_New();

65126522

if (dict == NULL)

65136523

return -1;

65146524

}

65156525

assert(PyDict_CheckExact(dict));

6516-

key = PyLong_FromVoidPtr((void *) type);

6517-

if (key == NULL)

6518-

return -1;

6519-

newobj = PyWeakref_NewRef((PyObject *)type, NULL);

6520-

if (newobj != NULL) {

6521-

result = PyDict_SetItem(dict, key, newobj);

6522-

Py_DECREF(newobj);

6523-

}

6526+
6527+

int result = PyDict_SetItem(dict, key, ref);

6528+

Py_DECREF(ref);

65246529

Py_DECREF(key);

65256530

return result;

65266531

}