Commit 44130af6 authored by Guido van Rossum's avatar Guido van Rossum

Jim Fulton reported a segfault in dir(). A heavily proxied object

returned a proxy for __class__ whose __bases__ was also a proxy.  The
merge_class_dict() helper for dir() assumed incorrectly that __bases__
would always be a tuple and used the in-line tuple API on the proxy.

I will backport this to 2.2 as well.
parent e7ab23bd
......@@ -365,6 +365,26 @@ def test_dir():
# object.
vereq(dir(None), dir(Ellipsis))
# Nasty test case for proxied objects
class Wrapper(object):
def __init__(self, obj):
self.__obj = obj
def __repr__(self):
return "Wrapper(%s)" % repr(self.__obj)
def __getitem__(self, key):
return Wrapper(self.__obj[key])
def __len__(self):
return len(self.__obj)
def __getattr__(self, name):
return Wrapper(getattr(self.__obj, name))
class C(object):
def __getclass(self):
return Wrapper(type(self))
__class__ = property(__getclass)
dir(C()) # This used to segfault
binops = {
'add': '+',
'sub': '-',
......
......@@ -1520,14 +1520,22 @@ merge_class_dict(PyObject* dict, PyObject* aclass)
if (bases == NULL)
PyErr_Clear();
else {
/* We have no guarantee that bases is a real tuple */
int i, n;
assert(PyTuple_Check(bases));
n = PyTuple_GET_SIZE(bases);
for (i = 0; i < n; i++) {
PyObject *base = PyTuple_GET_ITEM(bases, i);
if (merge_class_dict(dict, base) < 0) {
Py_DECREF(bases);
return -1;
n = PySequence_Size(bases); /* This better be right */
if (n < 0)
PyErr_Clear();
else {
for (i = 0; i < n; i++) {
PyObject *base = PySequence_GetItem(bases, i);
if (base == NULL) {
Py_DECREF(bases);
return -1;
}
if (merge_class_dict(dict, base) < 0) {
Py_DECREF(bases);
return -1;
}
}
}
Py_DECREF(bases);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment