diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2022-01-22 06:28:42 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-22 15:28:42 +0100 |
commit | f1796f29478f08f34e0c30a060622c0b2d843e2c (patch) | |
tree | 06bcdcf9a0ccb4d0edbd6d45d2b43ca711b4be49 | |
parent | 6ed874f8c59cc6c01d9663bad2f4bed8dc1c6109 (diff) | |
download | cpython-git-f1796f29478f08f34e0c30a060622c0b2d843e2c.tar.gz |
bpo-46417: Fix race condition on setting type __bases__ (GH-30788) (GH-30790)
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.
(cherry picked from commit f1c6ae3270913e095d24ae13ecf96f5a32c8c503)
Co-authored-by: Victor Stinner <vstinner@python.org>
Co-authored-by: Victor Stinner <vstinner@python.org>
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2022-01-22-14-39-23.bpo-46417.3U5SfN.rst | 5 | ||||
-rw-r--r-- | Objects/typeobject.c | 27 |
2 files changed, 21 insertions, 11 deletions
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-22-14-39-23.bpo-46417.3U5SfN.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-22-14-39-23.bpo-46417.3U5SfN.rst new file mode 100644 index 0000000000..54fe09b7ba --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-01-22-14-39-23.bpo-46417.3U5SfN.rst @@ -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. diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 1cdf80bfcf..d9ea9e8626 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5622,24 +5622,29 @@ PyType_Ready(PyTypeObject *type) static int add_subclass(PyTypeObject *base, PyTypeObject *type) { - int result = -1; - PyObject *dict, *key, *newobj; + PyObject *key = PyLong_FromVoidPtr((void *) type); + 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) { base->tp_subclasses = dict = PyDict_New(); if (dict == NULL) return -1; } assert(PyDict_CheckExact(dict)); - key = PyLong_FromVoidPtr((void *) type); - if (key == NULL) - return -1; - newobj = PyWeakref_NewRef((PyObject *)type, NULL); - if (newobj != NULL) { - result = PyDict_SetItem(dict, key, newobj); - Py_DECREF(newobj); - } + + int result = PyDict_SetItem(dict, key, ref); + Py_DECREF(ref); Py_DECREF(key); return result; } |