From 4402241450fe679a3cc90e4491aaabee232bb4e2 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Mon, 13 May 2002 18:29:46 +0000 Subject: 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. --- Lib/test/test_descr.py | 20 ++++++++++++++++++++ Objects/object.c | 22 +++++++++++++++------- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py index 353d0f2..e7e4a8f 100644 --- a/Lib/test/test_descr.py +++ b/Lib/test/test_descr.py @@ -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': '-', diff --git a/Objects/object.c b/Objects/object.c index 85fd35f..1bd8db9 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -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); -- cgit v0.12