summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2022-01-22 06:28:42 -0800
committerGitHub <noreply@github.com>2022-01-22 15:28:42 +0100
commitf1796f29478f08f34e0c30a060622c0b2d843e2c (patch)
tree06bcdcf9a0ccb4d0edbd6d45d2b43ca711b4be49
parent6ed874f8c59cc6c01d9663bad2f4bed8dc1c6109 (diff)
downloadcpython-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.rst5
-rw-r--r--Objects/typeobject.c27
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;
}