]> granicus.if.org Git - python/commitdiff
Jim Fulton reported a segfault in dir(). A heavily proxied object
authorGuido van Rossum <guido@python.org>
Mon, 13 May 2002 18:29:46 +0000 (18:29 +0000)
committerGuido van Rossum <guido@python.org>
Mon, 13 May 2002 18:29:46 +0000 (18:29 +0000)
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
Objects/object.c

index 353d0f28b4c02a19399bd91744381852ec5a5407..e7e4a8f2bb80d2b255dae0fe0b0baa59e7bb2b49 100644 (file)
@@ -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': '-',
index 85fd35fc6b145c92198d9ced2ba2e5554bbacad2..1bd8db924d8dd9ba27f7dc5791640ad26598f25d 100644 (file)
@@ -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);