Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4402241

Browse files
committed
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.
1 parent df4dabd commit 4402241

2 files changed

Lines changed: 35 additions & 7 deletions

File tree

Lib/test/test_descr.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,26 @@ def getdict(self):
365365
# object.
366366
vereq(dir(None), dir(Ellipsis))
367367

368+
# Nasty test case for proxied objects
369+
class Wrapper(object):
370+
def __init__(self, obj):
371+
self.__obj = obj
372+
def __repr__(self):
373+
return "Wrapper(%s)" % repr(self.__obj)
374+
def __getitem__(self, key):
375+
return Wrapper(self.__obj[key])
376+
def __len__(self):
377+
return len(self.__obj)
378+
def __getattr__(self, name):
379+
return Wrapper(getattr(self.__obj, name))
380+
381+
class C(object):
382+
def __getclass(self):
383+
return Wrapper(type(self))
384+
__class__ = property(__getclass)
385+
386+
dir(C()) # This used to segfault
387+
368388
binops = {
369389
'add': '+',
370390
'sub': '-',

Objects/object.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,14 +1520,22 @@ merge_class_dict(PyObject* dict, PyObject* aclass)
15201520
if (bases == NULL)
15211521
PyErr_Clear();
15221522
else {
1523+
/* We have no guarantee that bases is a real tuple */
15231524
int i, n;
1524-
assert(PyTuple_Check(bases));
1525-
n = PyTuple_GET_SIZE(bases);
1526-
for (i = 0; i < n; i++) {
1527-
PyObject *base = PyTuple_GET_ITEM(bases, i);
1528-
if (merge_class_dict(dict, base) < 0) {
1529-
Py_DECREF(bases);
1530-
return -1;
1525+
n = PySequence_Size(bases); /* This better be right */
1526+
if (n < 0)
1527+
PyErr_Clear();
1528+
else {
1529+
for (i = 0; i < n; i++) {
1530+
PyObject *base = PySequence_GetItem(bases, i);
1531+
if (base == NULL) {
1532+
Py_DECREF(bases);
1533+
return -1;
1534+
}
1535+
if (merge_class_dict(dict, base) < 0) {
1536+
Py_DECREF(bases);
1537+
return -1;
1538+
}
15311539
}
15321540
}
15331541
Py_DECREF(bases);

0 commit comments

Comments
 (0)