[Python-checkins] gh-92112: Fix crash triggered by an evil custom `mro()` (#92113)
JelleZijlstra
webhook-mailer at python.org
Fri May 6 00:01:19 EDT 2022
https://github.com/python/cpython/commit/85354ed78c0edb6d81a2bd53cabc85e547b8b26e
commit: 85354ed78c0edb6d81a2bd53cabc85e547b8b26e
branch: main
author: Alexey Izbyshev <izbyshev at ispras.ru>
committer: JelleZijlstra <jelle.zijlstra at gmail.com>
date: 2022-05-05T21:01:15-07:00
summary:
gh-92112: Fix crash triggered by an evil custom `mro()` (#92113)
files:
A Misc/NEWS.d/next/Core and Builtins/2022-05-01-10-58-38.gh-issue-92112.lLJemu.rst
M Lib/test/test_descr.py
M Objects/typeobject.c
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 48d43d7af85d9..afe0f7e9c7fd4 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -5784,6 +5784,23 @@ def mro(cls):
class A(metaclass=M):
pass
+ def test_disappearing_custom_mro(self):
+ """
+ gh-92112: A custom mro() returning a result conflicting with
+ __bases__ and deleting itself caused a double free.
+ """
+ class B:
+ pass
+
+ class M(DebugHelperMeta):
+ def mro(cls):
+ del M.mro
+ return (B,)
+
+ with self.assertRaises(TypeError):
+ class A(metaclass=M):
+ pass
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-05-01-10-58-38.gh-issue-92112.lLJemu.rst b/Misc/NEWS.d/next/Core and Builtins/2022-05-01-10-58-38.gh-issue-92112.lLJemu.rst
new file mode 100644
index 0000000000000..00c938e89f438
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-05-01-10-58-38.gh-issue-92112.lLJemu.rst
@@ -0,0 +1 @@
+Fix crash triggered by an evil custom ``mro()`` on a metaclass.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 4afaf240da1d1..1bcfd9a9c52bc 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -345,22 +345,26 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
Py_ssize_t i, n;
int custom = !Py_IS_TYPE(type, &PyType_Type);
int unbound;
- PyObject *mro_meth = NULL;
- PyObject *type_mro_meth = NULL;
if (custom) {
+ PyObject *mro_meth, *type_mro_meth;
mro_meth = lookup_maybe_method(
(PyObject *)type, &_Py_ID(mro), &unbound);
- if (mro_meth == NULL)
+ if (mro_meth == NULL) {
goto clear;
+ }
type_mro_meth = lookup_maybe_method(
(PyObject *)&PyType_Type, &_Py_ID(mro), &unbound);
- if (type_mro_meth == NULL)
+ if (type_mro_meth == NULL) {
+ Py_DECREF(mro_meth);
goto clear;
- if (mro_meth != type_mro_meth)
+ }
+ int custom_mro = (mro_meth != type_mro_meth);
+ Py_DECREF(mro_meth);
+ Py_DECREF(type_mro_meth);
+ if (custom_mro) {
goto clear;
- Py_XDECREF(mro_meth);
- Py_XDECREF(type_mro_meth);
+ }
}
n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) {
@@ -373,8 +377,6 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
}
return;
clear:
- Py_XDECREF(mro_meth);
- Py_XDECREF(type_mro_meth);
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
type->tp_version_tag = 0; /* 0 is not a valid version tag */
}
More information about the Python-checkins
mailing list