From 037d1e0ff38f4ae2867c4b90d263ecd8aa2df585 Mon Sep 17 00:00:00 2001 From: Armin Rigo Date: Thu, 29 Dec 2005 17:07:39 +0000 Subject: [PATCH] SF bug #1153075: "PyXxx_Check(x) trusts x->ob_type->tp_mro". A patch by mwh to check that user-defined mro's are reasonable enough. --- Lib/test/test_descr.py | 31 +++++++++++++++++++++++++++++++ Objects/typeobject.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 2ea8186846e..e954a0fb2aa 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -1635,6 +1635,37 @@ def altmro(): vereq(X.__mro__, (object, A, C, B, D, X)) vereq(X().f(), "A") + try: + class X(object): + class __metaclass__(type): + def mro(self): + return [self, dict, object] + except TypeError: + pass + else: + raise TestFailed, "devious mro() return not caught" + + try: + class X(object): + class __metaclass__(type): + def mro(self): + return [1] + except TypeError: + pass + else: + raise TestFailed, "non-class mro() return not caught" + + try: + class X(object): + class __metaclass__(type): + def mro(self): + return 1 + except TypeError: + pass + else: + raise TestFailed, "non-sequence mro() return not caught" + + def overloading(): if verbose: print "Testing operator overloading..." diff --git a/Objects/typeobject.c b/Objects/typeobject.c index b74fa1ad9f9..b403f646c43 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1288,12 +1288,14 @@ static int mro_internal(PyTypeObject *type) { PyObject *mro, *result, *tuple; + int checkit = 0; if (type->ob_type == &PyType_Type) { result = mro_implementation(type); } else { static PyObject *mro_str; + checkit = 1; mro = lookup_method((PyObject *)type, "mro", &mro_str); if (mro == NULL) return -1; @@ -1304,6 +1306,37 @@ mro_internal(PyTypeObject *type) return -1; tuple = PySequence_Tuple(result); Py_DECREF(result); + if (tuple == NULL) + return -1; + if (checkit) { + int i, len; + PyObject *cls; + PyTypeObject *solid; + + solid = solid_base(type); + + len = PyTuple_GET_SIZE(tuple); + + for (i = 0; i < len; i++) { + PyTypeObject *t; + cls = PyTuple_GET_ITEM(tuple, i); + if (PyClass_Check(cls)) + continue; + else if (!PyType_Check(cls)) { + PyErr_Format(PyExc_TypeError, + "mro() returned a non-class ('%.500s')", + cls->ob_type->tp_name); + return -1; + } + t = (PyTypeObject*)cls; + if (!PyType_IsSubtype(solid, solid_base(t))) { + PyErr_Format(PyExc_TypeError, + "mro() returned base with unsuitable layout ('%.500s')", + t->tp_name); + return -1; + } + } + } type->tp_mro = tuple; return 0; }