Naive approach to fix memview incref/decref asymmetry in transpose
authorMatěj Laitl <matej@laitl.cz>
Sat, 30 Mar 2013 16:13:47 +0000 (17:13 +0100)
committerMatěj Laitl <matej@laitl.cz>
Sat, 30 Mar 2013 16:13:47 +0000 (17:13 +0100)
This patch contains test-case along with a blind patch that fixes the test (but
may have other consequences, someone who actually understands the code must
review it).

Original error was:
Fatal Python error: Acquisition count is 0 (line XYZ)

which was caused by refcount error when memview transposition was used on
extension class memoryview attribute.

Cython/Compiler/ExprNodes.py
tests/memoryview/transpose_refcount.pyx [new file with mode: 0644]

index 08150c4..66e7359 100755 (executable)
@@ -5254,6 +5254,16 @@ class AttributeNode(ExprNode):
                 # C method implemented as function call with utility code
                 code.globalstate.use_utility_code(self.entry.utility_code)
 
+    def generate_disposal_code(self, code):
+        if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose:
+            # mirror condition for putting the memview incref here:
+            if self.obj.is_name or (self.obj.is_attribute and
+                                    self.obj.is_memslice_transpose):
+                code.put_xdecref_memoryviewslice(
+                        self.result(), have_gil=True)
+        else:
+            ExprNode.generate_disposal_code(self, code)
+
     def generate_assignment_code(self, rhs, code):
         self.obj.generate_evaluation_code(code)
         if self.is_py_attr:
diff --git a/tests/memoryview/transpose_refcount.pyx b/tests/memoryview/transpose_refcount.pyx
new file mode 100644 (file)
index 0000000..207bf53
--- /dev/null
@@ -0,0 +1,29 @@
+# mode: run
+
+from cython cimport view
+
+cdef bint print_upper_right(double[:, :] M):
+    print M[0, 1]
+
+cdef class MemViewContainer:
+    cdef double[:, :] A
+
+    def __init__(self, A):
+        self.A = A
+
+    cpdef run(self):
+        print_upper_right(self.A)
+        print_upper_right(self.A.T)
+        print_upper_right(self.A.T)
+
+def test_transpose_refcount():
+    """
+    >>> test_transpose_refcount()
+    2.0
+    3.0
+    3.0
+    """
+    cdef double[:, :] A = view.array(shape=(2, 2), itemsize=sizeof(double), format="d")
+    A[0, 0], A[0, 1], A[1, 0], A[1, 1] = 1., 2., 3., 4.
+    cdef MemViewContainer container = MemViewContainer(A)
+    container.run()