[pypy-commit] pypy default: Issue #2629

arigo pypy.commits at gmail.com
Mon Aug 14 13:15:46 EDT 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r92147:8775f1e1bf8b
Date: 2017-08-14 19:14 +0200
http://bitbucket.org/pypy/pypy/changeset/8775f1e1bf8b/

Log:	Issue #2629

	Uninitialized instances of 'property' or 'super' should not cause
	segfaults

diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py
--- a/pypy/module/__builtin__/descriptor.py
+++ b/pypy/module/__builtin__/descriptor.py
@@ -28,12 +28,19 @@
             objtype_name = "<%s object>" % self.w_objtype.getname(space)
         else:
             objtype_name = 'NULL'
+        if self.w_starttype is not None:
+            starttype_name = self.w_starttype.getname(space)
+        else:
+            starttype_name = 'NULL'
         return space.newtext("<super: <class '%s'>, %s>" % (
-            self.w_starttype.getname(space), objtype_name))
+            starttype_name, objtype_name))
 
     def get(self, space, w_obj, w_type=None):
         if self.w_self is not None or space.is_w(w_obj, space.w_None):
             return self
+        if self.w_starttype is None:
+            raise oefmt(space.w_TypeError,
+                "__get__(x) is invalid on an uninitialized instance of 'super'")
         else:
             # if type(self) is W_Super:
             #     XXX write a fast path for this common case
@@ -45,6 +52,7 @@
         # only use a special logic for bound super objects and not for
         # getting the __class__ of the super object itself.
         if self.w_objtype is not None and name != '__class__':
+            assert self.w_starttype is not None
             w_value = space.lookup_in_type_starting_at(self.w_objtype,
                                                        self.w_starttype,
                                                        name)
@@ -114,7 +122,11 @@
     _immutable_fields_ = ["w_fget", "w_fset", "w_fdel"]
 
     def __init__(self, space):
-        pass
+        self.w_fget = space.w_None
+        self.w_fset = space.w_None
+        self.w_fdel = space.w_None
+        self.w_doc = space.w_None
+        self.getter_doc = False
 
     @unwrap_spec(w_fget=WrappedDefault(None),
                  w_fset=WrappedDefault(None),
diff --git a/pypy/module/__builtin__/test/test_descriptor.py b/pypy/module/__builtin__/test/test_descriptor.py
--- a/pypy/module/__builtin__/test/test_descriptor.py
+++ b/pypy/module/__builtin__/test/test_descriptor.py
@@ -419,3 +419,35 @@
         assert x.y == 42
         del x.x
         assert x.z == 42
+
+    def test_uninitialized_property(self):
+        p = property.__new__(property)
+        raises(AttributeError, p.__get__, 42)
+        raises(AttributeError, p.__set__, 42, None)
+        raises(AttributeError, p.__delete__, 42)
+        assert repr(p).startswith("<property object at ")
+        assert p.fget is p.fset is p.fdel is p.__doc__ is None
+        #
+        lst = []
+        p.deleter(lst.append).__delete__(42)
+        assert lst == [42]
+        #
+        lst = []
+        p.getter(lst.append).__get__(43)
+        assert lst == [43]
+        #
+        lst = []
+        p.setter(lambda x, y: lst.append((x, y))).__set__(44, 45)
+        assert lst == [(44, 45)]
+
+    def test_uninitialized_super(self):
+        s = super.__new__(super)
+        assert repr(s) == "<super: <class 'NULL'>, NULL>"
+        assert s.__thisclass__ is s.__self__ is s.__self_class__ is None
+        assert s.__get__(None, "anything") is s
+        raises(TypeError, s.__get__, 42)
+        raises(TypeError, s.__get__, int)
+        raises(TypeError, s.__get__, type(None))
+        raises(AttributeError, "s.abcde")
+        raises(AttributeError, "s.abcde = 42")
+        raises(AttributeError, "del s.abcde")


More information about the pypy-commit mailing list