Author: Antonio Cuni <anto.c...@gmail.com>
Branch: fix-cpyext-releasebuffer
Changeset: r90432:0d60d6a74fdc
Date: 2017-02-28 23:09 +0100
http://bitbucket.org/pypy/pypy/changeset/0d60d6a74fdc/

Log:    (antocuni, rlamy): modify an existing test to show broken behavior:
        the correct way to implement bf_getbuffer is to do a Py_INCREF(obj),
        which the broken test didn't. Once you do, you notice that cpyext
        never does the corresponding decref, thus causing a leak because the
        original object is never deallocated

diff --git a/pypy/module/cpyext/test/test_bufferobject.py 
b/pypy/module/cpyext/test/test_bufferobject.py
--- a/pypy/module/cpyext/test/test_bufferobject.py
+++ b/pypy/module/cpyext/test/test_bufferobject.py
@@ -73,16 +73,27 @@
                 return obj;
              """),
             ("get_cnt", "METH_NOARGS",
-             'return PyLong_FromLong(cnt);')], prologue="""
+             'return PyLong_FromLong(cnt);'),
+            ("get_dealloc_cnt", "METH_NOARGS",
+             'return PyLong_FromLong(dealloc_cnt);'),
+        ],
+        prologue="""
                 static float test_data = 42.f;
                 static int cnt=0;
+                static int dealloc_cnt=0;
                 static PyHeapTypeObject * type=NULL;
 
+                void dealloc(PyObject *self) {
+                    dealloc_cnt++;
+                }
                 int getbuffer(PyObject *obj, Py_buffer *view, int flags) {
 
                     cnt ++;
                     memset(view, 0, sizeof(Py_buffer));
                     view->obj = obj;
+                    /* see the CPython docs for why we need this incref:
+                       
https://docs.python.org/3.5/c-api/typeobj.html#c.PyBufferProcs.bf_getbuffer */
+                    Py_INCREF(obj);
                     view->ndim = 0;
                     view->buf = (void *) &test_data;
                     view->itemsize = sizeof(float);
@@ -96,7 +107,7 @@
                 void releasebuffer(PyObject *obj, Py_buffer *view) { 
                     cnt --;
                 }
-            """, more_init="""
+            """, more_init="""            
                 type = (PyHeapTypeObject *) PyType_Type.tp_alloc(&PyType_Type, 
0);
 
                 type->ht_type.tp_name = "Test";
@@ -106,6 +117,7 @@
                                           Py_TPFLAGS_HEAPTYPE | 
Py_TPFLAGS_HAVE_NEWBUFFER;
                 type->ht_type.tp_flags &= ~Py_TPFLAGS_HAVE_GC;
 
+                type->ht_type.tp_dealloc = dealloc;
                 type->ht_type.tp_as_buffer = &type->as_buffer;
                 type->as_buffer.bf_getbuffer = getbuffer;
                 type->as_buffer.bf_releasebuffer = releasebuffer;
@@ -116,6 +128,8 @@
         assert module.get_cnt() == 0
         a = memoryview(module.create_test())
         assert module.get_cnt() == 1
+        assert module.get_dealloc_cnt() == 0
         del a
-        gc.collect(); gc.collect(); gc.collect()
+        self.debug_collect()
         assert module.get_cnt() == 0
+        assert module.get_dealloc_cnt() == 1
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to