From f82b32410ba220165eab7b8d6dcc61a09744512c Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra <jelle.zijlstra@gmail.com> Date: Mon, 16 May 2022 09:47:35 -0700 Subject: [PATCH] [3.9] gh-92112: Fix crash triggered by an evil custom `mro()` (GH-92113) (GH-92372) (cherry picked from commit 85354ed78c0edb6d81a2bd53cabc85e547b8b26e) Co-authored-by: Alexey Izbyshev <izbyshev@ispras.ru> --- Lib/test/test_descr.py | 17 ++++++++++++++++ ...2-05-01-10-58-38.gh-issue-92112.lLJemu.rst | 1 + Objects/typeobject.c | 20 ++++++++++--------- 3 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-05-01-10-58-38.gh-issue-92112.lLJemu.rst diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index e5e9f493969..a8fe3ef6cdf 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -5686,6 +5686,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 00000000000..00c938e89f4 --- /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 cb0bb46145c..755d3361916 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -317,25 +317,29 @@ 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 (!_PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG)) return; 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++) { @@ -352,8 +356,6 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) { } return; clear: - Py_XDECREF(mro_meth); - Py_XDECREF(type_mro_meth); type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG| Py_TPFLAGS_VALID_VERSION_TAG); } -- GitLab