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.
This commit is contained in:
parent
f5bd3b442d
commit
037d1e0ff3
|
@ -1635,6 +1635,37 @@ def altmro():
|
||||||
vereq(X.__mro__, (object, A, C, B, D, X))
|
vereq(X.__mro__, (object, A, C, B, D, X))
|
||||||
vereq(X().f(), "A")
|
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():
|
def overloading():
|
||||||
if verbose: print "Testing operator overloading..."
|
if verbose: print "Testing operator overloading..."
|
||||||
|
|
||||||
|
|
|
@ -1288,12 +1288,14 @@ static int
|
||||||
mro_internal(PyTypeObject *type)
|
mro_internal(PyTypeObject *type)
|
||||||
{
|
{
|
||||||
PyObject *mro, *result, *tuple;
|
PyObject *mro, *result, *tuple;
|
||||||
|
int checkit = 0;
|
||||||
|
|
||||||
if (type->ob_type == &PyType_Type) {
|
if (type->ob_type == &PyType_Type) {
|
||||||
result = mro_implementation(type);
|
result = mro_implementation(type);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
static PyObject *mro_str;
|
static PyObject *mro_str;
|
||||||
|
checkit = 1;
|
||||||
mro = lookup_method((PyObject *)type, "mro", &mro_str);
|
mro = lookup_method((PyObject *)type, "mro", &mro_str);
|
||||||
if (mro == NULL)
|
if (mro == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1304,6 +1306,37 @@ mro_internal(PyTypeObject *type)
|
||||||
return -1;
|
return -1;
|
||||||
tuple = PySequence_Tuple(result);
|
tuple = PySequence_Tuple(result);
|
||||||
Py_DECREF(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;
|
type->tp_mro = tuple;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue