]> granicus.if.org Git - python/commitdiff
SF bug #1153075: "PyXxx_Check(x) trusts x->ob_type->tp_mro".
authorArmin Rigo <arigo@tunes.org>
Thu, 29 Dec 2005 17:07:39 +0000 (17:07 +0000)
committerArmin Rigo <arigo@tunes.org>
Thu, 29 Dec 2005 17:07:39 +0000 (17:07 +0000)
A patch by mwh to check that user-defined mro's are reasonable
enough.

Lib/test/test_descr.py
Objects/typeobject.c

index 2ea8186846e8470b411a152ac2cedc0dcb56b523..e954a0fb2aacb0aa82c3a0f636d3fbcaed2bf967 100644 (file)
@@ -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..."
 
index b74fa1ad9f9450e8eb2b314fe8b38f86ef3ffb1d..b403f646c434946e93c71bf840e68febc670bdcd 100644 (file)
@@ -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;
 }