[Python-checkins] [3.10] gh-92112: Fix crash triggered by an evil custom `mro()` (GH-92113) (#92370)

JelleZijlstra webhook-mailer at python.org
Sat May 7 00:01:54 EDT 2022


https://github.com/python/cpython/commit/4674b315e555828e5cb15bedcf2c495669670cbb
commit: 4674b315e555828e5cb15bedcf2c495669670cbb
branch: 3.10
author: Jelle Zijlstra <jelle.zijlstra at gmail.com>
committer: JelleZijlstra <jelle.zijlstra at gmail.com>
date: 2022-05-06T21:01:23-07:00
summary:

[3.10] gh-92112: Fix crash triggered by an evil custom `mro()` (GH-92113) (#92370)

(cherry picked from commit 85354ed78c0edb6d81a2bd53cabc85e547b8b26e)

Co-authored-by: Alexey Izbyshev <izbyshev at ispras.ru>

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 f3dd1b32e2afa..b174e7168f7db 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -5737,6 +5737,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 b3ba1208eb253..50f2742f676f6 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -369,22 +369,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, &PyId_mro, &unbound);
-        if (mro_meth == NULL)
+        if (mro_meth == NULL) {
             goto clear;
+        }
         type_mro_meth = lookup_maybe_method(
             (PyObject *)&PyType_Type, &PyId_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++) {
@@ -400,8 +404,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