mirror of https://github.com/python/cpython
bpo-46417: Fix race condition on setting type __bases__ (GH-30788)
Fix a race condition on setting a type __bases__ attribute: the internal function add_subclass() now gets the PyTypeObject.tp_subclasses member after calling PyWeakref_NewRef() which can trigger a garbage collection which can indirectly modify PyTypeObject.tp_subclasses.
This commit is contained in:
parent
c8a536624e
commit
f1c6ae3270
|
@ -0,0 +1,5 @@
|
||||||
|
Fix a race condition on setting a type ``__bases__`` attribute: the internal
|
||||||
|
function ``add_subclass()`` now gets the ``PyTypeObject.tp_subclasses``
|
||||||
|
member after calling :c:func:`PyWeakref_NewRef` which can trigger a garbage
|
||||||
|
collection which can indirectly modify ``PyTypeObject.tp_subclasses``. Patch
|
||||||
|
by Victor Stinner.
|
|
@ -6503,24 +6503,29 @@ PyType_Ready(PyTypeObject *type)
|
||||||
static int
|
static int
|
||||||
add_subclass(PyTypeObject *base, PyTypeObject *type)
|
add_subclass(PyTypeObject *base, PyTypeObject *type)
|
||||||
{
|
{
|
||||||
int result = -1;
|
PyObject *key = PyLong_FromVoidPtr((void *) type);
|
||||||
PyObject *dict, *key, *newobj;
|
if (key == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
dict = base->tp_subclasses;
|
PyObject *ref = PyWeakref_NewRef((PyObject *)type, NULL);
|
||||||
|
if (ref == NULL) {
|
||||||
|
Py_DECREF(key);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only get tp_subclasses after creating the key and value.
|
||||||
|
// PyWeakref_NewRef() can trigger a garbage collection which can execute
|
||||||
|
// arbitrary Python code and so modify base->tp_subclasses.
|
||||||
|
PyObject *dict = base->tp_subclasses;
|
||||||
if (dict == NULL) {
|
if (dict == NULL) {
|
||||||
base->tp_subclasses = dict = PyDict_New();
|
base->tp_subclasses = dict = PyDict_New();
|
||||||
if (dict == NULL)
|
if (dict == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
assert(PyDict_CheckExact(dict));
|
assert(PyDict_CheckExact(dict));
|
||||||
key = PyLong_FromVoidPtr((void *) type);
|
|
||||||
if (key == NULL)
|
int result = PyDict_SetItem(dict, key, ref);
|
||||||
return -1;
|
Py_DECREF(ref);
|
||||||
newobj = PyWeakref_NewRef((PyObject *)type, NULL);
|
|
||||||
if (newobj != NULL) {
|
|
||||||
result = PyDict_SetItem(dict, key, newobj);
|
|
||||||
Py_DECREF(newobj);
|
|
||||||
}
|
|
||||||
Py_DECREF(key);
|
Py_DECREF(key);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue