Commit 73c6b0ea authored by Mark Florisson's avatar Mark Florisson

Allow nogil bounds checking for buffers/memoryviews

parent 49e7d509
......@@ -412,7 +412,7 @@ def put_assign_to_buffer(lhs_cname, rhs_cname, buf_entry,
code.putln("}") # Release stack
def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives,
pos, code, negative_indices):
pos, code, negative_indices, in_nogil_context):
"""
Generates code to process indices and calculate an offset into
a buffer. Returns a C string which gives a pointer which can be
......@@ -455,9 +455,16 @@ def put_buffer_lookup_code(entry, index_signeds, index_cnames, directives,
code.putln("if (%s) %s = %d;" % (
code.unlikely("%s >= %s%s" % (cname, cast, shape)),
tmp_cname, dim))
code.globalstate.use_utility_code(raise_indexerror_code)
if in_nogil_context:
code.globalstate.use_utility_code(raise_indexerror_nogil)
func = '__Pyx_RaiseBufferIndexErrorNogil'
else:
code.globalstate.use_utility_code(raise_indexerror_code)
func = '__Pyx_RaiseBufferIndexError'
code.putln("if (%s) {" % code.unlikely("%s != -1" % tmp_cname))
code.putln('__Pyx_RaiseBufferIndexError(%s);' % tmp_cname)
code.putln('%s(%s);' % (func, tmp_cname))
code.putln(code.error_goto(pos))
code.putln('}')
code.funcstate.release_temp(tmp_cname)
......@@ -768,6 +775,7 @@ buffer_struct_declare_code = load_buffer_utility("BufferStructDeclare",
# Utility function to set the right exception
# The caller should immediately goto_error
raise_indexerror_code = load_buffer_utility("BufferIndexError")
raise_indexerror_nogil = load_buffer_utility("BufferIndexErrorNogil")
parse_typestring_repeat_code = UtilityCode(
proto = """
......
......@@ -2812,9 +2812,11 @@ class IndexNode(ExprNode):
def nogil_check(self, env):
if self.is_buffer_access or self.memslice_index or self.memslice_slice:
if not self.memslice_slice and 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 check buffer index bounds without gil; "
# "use boundscheck(False) directive")
warning(self.pos, "Use boundscheck(False) for faster access",
level=1)
if self.type.is_pyobject:
error(self.pos, "Cannot access buffer with object dtype without gil")
return
super(IndexNode, self).nogil_check(env)
......@@ -3084,7 +3086,8 @@ class IndexNode(ExprNode):
index_cnames=index_temps,
directives=code.globalstate.directives,
pos=self.pos, code=code,
negative_indices=negative_indices)
negative_indices=negative_indices,
in_nogil_context=self.in_nogil_context)
def put_memoryviewslice_slice_code(self, code):
"memslice[:]"
......@@ -9681,7 +9684,7 @@ static void __Pyx_RaiseUnboundMemoryviewSliceNogil(const char *varname) {
PyGILState_STATE gilstate = PyGILState_Ensure();
#endif
__Pyx_RaiseUnboundLocalError(varname);
#ifdef WITH_THREAD")
#ifdef WITH_THREAD
PyGILState_Release(gilstate);
#endif
}
......
......@@ -26,6 +26,22 @@ static void __Pyx_RaiseBufferIndexError(int axis) {
"Out of bounds on buffer access (axis %d)", axis);
}
/////////////// BufferIndexErrorNogil.proto ///////////////
//@requires: BufferIndexError
static void __Pyx_RaiseBufferIndexErrorNogil(int axis); /*proto*/
/////////////// BufferIndexErrorNogil ///////////////
static void __Pyx_RaiseBufferIndexErrorNogil(int axis) {
#ifdef WITH_THREAD
PyGILState_STATE gilstate = PyGILState_Ensure();
#endif
__Pyx_RaiseBufferIndexError(axis);
#ifdef WITH_THREAD
PyGILState_Release(gilstate);
#endif
}
/////////////// BufferFallbackError.proto ///////////////
static void __Pyx_RaiseBufferFallbackError(void); /*proto*/
......
......@@ -1114,3 +1114,16 @@ def buffer_nogil():
with nogil:
buf[1] = 10
return buf[1]
@testcase
def buffer_nogil_oob():
"""
>>> buffer_nogil_oob()
Traceback (most recent call last):
...
IndexError: Out of bounds on buffer access (axis 0)
"""
cdef object[int] buf = IntMockBuffer(None, [1,2,3])
with nogil:
buf[5] = 10
return buf[1]
......@@ -209,6 +209,18 @@ def test_nogil_unbound_localerror():
with nogil:
m[0] = 10
def test_nogil_oob():
"""
>>> test_nogil_oob()
Traceback (most recent call last):
...
IndexError: Out of bounds on buffer access (axis 0)
"""
cdef int[5] a
cdef int[:] m = a
with nogil:
m[5] = 1
def basic_struct(MyStruct[:] mslice):
"""
See also buffmt.pyx
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment