diff options
author | Armin Rigo <arigo@tunes.org> | 2005-12-29 17:07:39 (GMT) |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2005-12-29 17:07:39 (GMT) |
commit | 037d1e0ff38f4ae2867c4b90d263ecd8aa2df585 (patch) | |
tree | 327d4acac79a49988505edca603e7475833a3d87 | |
parent | f5bd3b442dd378563036f51595a7d6b2a239f4d5 (diff) | |
download | cpython-037d1e0ff38f4ae2867c4b90d263ecd8aa2df585.zip cpython-037d1e0ff38f4ae2867c4b90d263ecd8aa2df585.tar.gz cpython-037d1e0ff38f4ae2867c4b90d263ecd8aa2df585.tar.bz2 |
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.
-rw-r--r-- | Lib/test/test_descr.py | 31 | ||||
-rw-r--r-- | Objects/typeobject.c | 33 |
2 files changed, 64 insertions, 0 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 2ea8186..e954a0f 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 b74fa1a..b403f64 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; } |