Proper nogil checks for buffer access
authorDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Wed, 15 Apr 2009 19:44:01 +0000 (21:44 +0200)
committerDag Sverre Seljebotn <dagss@student.matnat.uio.no>
Wed, 15 Apr 2009 19:44:01 +0000 (21:44 +0200)
Cython/Compiler/ExprNodes.py
tests/errors/e_bufaccess2.pyx
tests/run/bufaccess.pyx

index 2abce3f392e26681d237e8084208a5867d840f8d..25f655a5b7877b8d9e692bb31c9aa7e96a5087a8 100644 (file)
@@ -1745,7 +1745,6 @@ class IndexNode(ExprNode):
                 else:
                     self.index = self.index.coerce_to_pyobject(env)
                 self.type = py_object_type
-                self.gil_check(env)
                 self.is_temp = 1
             else:
                 if self.base.type.is_ptr or self.base.type.is_array:
@@ -1762,9 +1761,21 @@ class IndexNode(ExprNode):
                     error(self.pos,
                         "Invalid index type '%s'" %
                             self.index.type)
+        self.gil_check(env)
 
     gil_message = "Indexing Python object"
 
+    def gil_check(self, env):
+        if self.is_buffer_access and env.nogil:
+            if env.directives['boundscheck']:
+                error(self.pos, "Cannot check buffer index bounds without gil; use boundscheck(False) directive")
+                return
+            elif self.type.is_pyobject:
+                error(self.pos, "Cannot access buffer with object dtype without gil")
+                return
+        super(IndexNode, self).gil_check(env)
+
+
     def check_const_addr(self):
         self.base.check_const_addr()
         self.index.check_const()
index 8310491525e4ca4cc921d005345f9b5eb908be84..24fc68a329c33796c03201e8b09a3bfef7b29628 100644 (file)
@@ -1,8 +1,35 @@
 cimport e_bufaccess_pxd # was needed to provoke a bug involving ErrorType
+import cython
 
 def f():
     cdef object[e_bufaccess_pxd.T] buf
 
+def withnogil_access_fail():
+    cdef object[int] buf = None
+    with nogil:
+        buf[2] = 2
+
+@cython.boundscheck(False)
+def withnogil_access_ok():
+    cdef object[int] buf = None
+    with nogil:
+        buf[2] = 2 # No error should be triggered here
+
+@cython.boundscheck(False)
+def withnogil_access_fail_2():
+    cdef object[object] buf = None
+    with nogil:
+        buf[2] = 2 # Not OK as dtype is object
+
+def withnogil_acquire(x):
+    cdef object[int] buf
+    with nogil:
+        buf = x
+
 _ERRORS = u"""
 3:9: 'nothing' is not a type identifier
+10:11: Cannot check buffer index bounds without gil; use boundscheck(False) directive
+22:11: Cannot access buffer with object dtype without gil
+22:11: Assignment of Python object not allowed without gil
+27:12: Assignment of Python object not allowed without gil
 """
index 50b4e6733a30d873eee75ad1602ab2675873d2bf..81d2238dd980a0ff6f81d5424f806caf18dceb8e 100644 (file)
@@ -1449,3 +1449,18 @@ def complex_struct_inplace(object[LongComplex] buf):
     buf[0].imag += 2
     print buf[0].real, buf[0].imag
     
+#
+# Nogil
+#
+@testcase
+@cython.boundscheck(False)
+def buffer_nogil():
+    """
+    >>> buffer_nogil()
+    10
+    """
+    cdef object[int] buf = IntMockBuffer(None, [1,2,3])
+    with nogil:
+        buf[1] = 10
+    return buf[1]
+