[pypy-commit] pypy default: Correctly initialize the d_type and d_name members of builtin descriptors.

rlamy pypy.commits at gmail.com
Sat Feb 23 17:39:57 EST 2019


Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: 
Changeset: r96141:5f79cbf51fda
Date: 2019-02-23 19:06 +0000
http://bitbucket.org/pypy/pypy/changeset/5f79cbf51fda/

Log:	Correctly initialize the d_type and d_name members of builtin
	descriptors.

	This fixes a segfault related to classmethods in Cython.

diff --git a/pypy/module/cpyext/methodobject.py b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -100,7 +100,7 @@
 
     def call_o(self, space, w_self, __args__):
         func = self.ml.c_ml_meth
-        w_o = __args__.arguments_w[0]        
+        w_o = __args__.arguments_w[0]
         return generic_cpy_call(space, func, w_self, w_o)
 
     def call_varargs(self, space, w_self, __args__):
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -146,8 +146,11 @@
 
     def test_cython_fake_classmethod(self):
         module = self.import_module(name='foo')
-        print(module.fooType.fake_classmeth)
-        print(type(module.fooType.fake_classmeth))
+
+        # Check that objects are printable
+        print(module.fooType.fake_classmeth)  # bound method on the class
+        print(module.fooType.__dict__['fake_classmeth']) # raw descriptor
+
         assert module.fooType.fake_classmeth() is module.fooType
 
     def test_new(self):
@@ -447,7 +450,7 @@
             pass
         obj = Sub()
         assert module.hack_tp_dict(obj, "b") == 2
-        
+
 
     def test_tp_descr_get(self):
         module = self.import_extension('foo', [
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -131,31 +131,58 @@
                    basestruct=cts.gettype('PyMemberDescrObject'),
                    attach=memberdescr_attach,
                    realize=memberdescr_realize,
+                   dealloc=descr_dealloc,
                    )
     make_typedescr(W_GetSetPropertyEx.typedef,
                    basestruct=cts.gettype('PyGetSetDescrObject'),
                    attach=getsetdescr_attach,
+                   dealloc=descr_dealloc,
                    )
     make_typedescr(W_PyCClassMethodObject.typedef,
                    basestruct=cts.gettype('PyMethodDescrObject'),
                    attach=methoddescr_attach,
                    realize=classmethoddescr_realize,
+                   dealloc=descr_dealloc,
                    )
     make_typedescr(W_PyCMethodObject.typedef,
                    basestruct=cts.gettype('PyMethodDescrObject'),
                    attach=methoddescr_attach,
                    realize=methoddescr_realize,
+                   dealloc=descr_dealloc,
                    )
 
+def init_descr(space, py_obj, w_type, c_name):
+    """Initialises the common fields in a PyDescrObject
+
+    Arguments:
+        py_obj: PyObject* pointer to a PyDescrObject
+        w_type: W_TypeObject
+        c_name: char*
+    """
+    from pypy.module.cpyext.unicodeobject import PyUnicode_FromString
+    py_descr = cts.cast('PyDescrObject*', py_obj)
+    py_descr.c_d_type = cts.cast(
+        'PyTypeObject*', make_ref(space, w_type))
+    py_descr.c_d_name = make_ref(
+        space, PyUnicode_FromString(space, c_name))
+
+ at slot_function([PyObject], lltype.Void)
+def descr_dealloc(space, py_obj):
+    from pypy.module.cpyext.object import _dealloc
+    py_descr = cts.cast('PyDescrObject*', py_obj)
+    decref(space, py_descr.c_d_type)
+    decref(space, py_descr.c_d_name)
+    _dealloc(space, py_obj)
+
 def memberdescr_attach(space, py_obj, w_obj, w_userdata=None):
     """
     Fills a newly allocated PyMemberDescrObject with the given W_MemberDescr
     object. The values must not be modified.
     """
     py_memberdescr = cts.cast('PyMemberDescrObject*', py_obj)
-    # XXX assign to d_dname, d_type?
     assert isinstance(w_obj, W_MemberDescr)
     py_memberdescr.c_d_member = w_obj.member
+    init_descr(space, py_obj, w_obj.w_type, w_obj.member.c_name)
 
 def memberdescr_realize(space, obj):
     # XXX NOT TESTED When is this ever called?
@@ -178,15 +205,15 @@
         w_obj = W_GetSetPropertyEx(py_getsetdef, w_userdata)
         # now w_obj.getset is py_getsetdef, which was freshly allocated
         # XXX how is this ever released?
-    # XXX assign to d_dname, d_type?
     assert isinstance(w_obj, W_GetSetPropertyEx)
     py_getsetdescr.c_d_getset = w_obj.getset
+    init_descr(space, py_obj, w_obj.w_type, w_obj.getset.c_name)
 
 def methoddescr_attach(space, py_obj, w_obj, w_userdata=None):
     py_methoddescr = cts.cast('PyMethodDescrObject*', py_obj)
-    # XXX assign to d_dname, d_type?
     assert isinstance(w_obj, W_PyCFunctionObject)
     py_methoddescr.c_d_method = w_obj.ml
+    init_descr(space, py_obj, w_obj.w_objclass, w_obj.ml.c_ml_name)
 
 def classmethoddescr_realize(space, obj):
     # XXX NOT TESTED When is this ever called?
@@ -206,6 +233,7 @@
     track_reference(space, obj, w_obj)
     return w_obj
 
+
 def convert_getset_defs(space, dict_w, getsets, w_type):
     getsets = rffi.cast(rffi.CArrayPtr(PyGetSetDef), getsets)
     if getsets:


More information about the pypy-commit mailing list