Commit c7265455 authored by Stefan Behnel's avatar Stefan Behnel

Disable auto-detection of read-only memory views (too unsafe) and acquire them...

Disable auto-detection of read-only memory views (too unsafe) and acquire them only as read-only if the memory view dtype is a "const" type.
parent 3531f69b
...@@ -15,10 +15,8 @@ Features added ...@@ -15,10 +15,8 @@ Features added
* Type inference is now supported for Pythran compiled NumPy expressions. * Type inference is now supported for Pythran compiled NumPy expressions.
Patch by Nils Braun. (Github issue #1954) Patch by Nils Braun. (Github issue #1954)
* Read-only buffers are automatically supported for memoryviews if it can be * The ``const`` modifier can be applied to memoryview declarations to allow
determined at compile time that the code does not need write access. read-only buffers as input. (Github issues #1605, #1869)
They can also be allowed explicitly by adding the ``const`` modifier to their
declaration. (Github issues #1605, #1869)
* When compiling with gcc, the module init function is now tuned for small * When compiling with gcc, the module init function is now tuned for small
code size instead of whatever compile flags were provided externally. code size instead of whatever compile flags were provided externally.
......
...@@ -907,9 +907,12 @@ class MemoryViewSliceType(PyrexType): ...@@ -907,9 +907,12 @@ class MemoryViewSliceType(PyrexType):
def from_py_call_code(self, source_code, result_code, error_pos, code, def from_py_call_code(self, source_code, result_code, error_pos, code,
from_py_function=None, error_condition=None): from_py_function=None, error_condition=None):
# NOTE: auto-detection of readonly buffers is disabled:
# writable = self.writable_needed or not self.dtype.is_const
writable = not self.dtype.is_const
return self._assign_from_py_code( return self._assign_from_py_code(
source_code, result_code, error_pos, code, from_py_function, error_condition, source_code, result_code, error_pos, code, from_py_function, error_condition,
extra_args=['PyBUF_WRITABLE' if self.writable_needed else '0']) extra_args=['PyBUF_WRITABLE' if writable else '0'])
def create_to_py_utility_code(self, env): def create_to_py_utility_code(self, env):
self._dtype_to_py_func, self._dtype_from_py_func = self.dtype_object_conversion_funcs(env) self._dtype_to_py_func, self._dtype_from_py_func = self.dtype_object_conversion_funcs(env)
...@@ -937,25 +940,29 @@ class MemoryViewSliceType(PyrexType): ...@@ -937,25 +940,29 @@ class MemoryViewSliceType(PyrexType):
if self.dtype.is_pyobject: if self.dtype.is_pyobject:
utility_name = "MemviewObjectToObject" utility_name = "MemviewObjectToObject"
else: else:
to_py = self.dtype.create_to_py_utility_code(env) self.dtype.create_to_py_utility_code(env)
from_py = self.dtype.create_from_py_utility_code(env) to_py_function = self.dtype.to_py_function
if not (to_py or from_py):
return "NULL", "NULL"
if not self.dtype.to_py_function: from_py_function = None
get_function = "NULL" if not self.dtype.is_const:
self.dtype.create_from_py_utility_code(env)
from_py_function = self.dtype.from_py_function
if not self.dtype.from_py_function: if not (to_py_function or from_py_function):
return "NULL", "NULL"
if not to_py_function:
get_function = "NULL"
if not from_py_function:
set_function = "NULL" set_function = "NULL"
utility_name = "MemviewDtypeToObject" utility_name = "MemviewDtypeToObject"
error_condition = (self.dtype.error_condition('value') or error_condition = (self.dtype.error_condition('value') or
'PyErr_Occurred()') 'PyErr_Occurred()')
context.update( context.update(
to_py_function = self.dtype.to_py_function, to_py_function=to_py_function,
from_py_function = self.dtype.from_py_function, from_py_function=from_py_function,
dtype = self.dtype.empty_declaration_code(), dtype=self.dtype.empty_declaration_code(),
error_condition = error_condition, error_condition=error_condition,
) )
utility = TempitaUtilityCode.load_cached( utility = TempitaUtilityCode.load_cached(
...@@ -2456,7 +2463,7 @@ class CArrayType(CPointerBaseType): ...@@ -2456,7 +2463,7 @@ class CArrayType(CPointerBaseType):
def from_py_call_code(self, source_code, result_code, error_pos, code, def from_py_call_code(self, source_code, result_code, error_pos, code,
from_py_function=None, error_condition=None): from_py_function=None, error_condition=None):
assert not error_condition assert not error_condition, '%s: %s' % (error_pos, error_condition)
call_code = "%s(%s, %s, %s)" % ( call_code = "%s(%s, %s, %s)" % (
from_py_function or self.from_py_function, from_py_function or self.from_py_function,
source_code, result_code, self.size) source_code, result_code, self.size)
......
...@@ -244,14 +244,14 @@ Note that this does not *require* the input to be read-only:: ...@@ -244,14 +244,14 @@ Note that this does not *require* the input to be read-only::
a = np.linspace(0, 10, num=50) a = np.linspace(0, 10, num=50)
myslice = a myslice = a
Writable buffers will still be accepted by ``const`` views, but read-only Writable buffers are still accepted by ``const`` views, but read-only
buffers are not accepted for non-const, writable views. buffers are not accepted for non-const, writable views::
Cython will also request a read-only view automatically if it can determine cdef double[:] myslice # a normal read-write memory view
at compile time that a writable buffer is not required. The support for
automatically distinguishing between buffer usage types, and the compile a = np.linspace(0, 10, num=50)
time correctness checks for read-only views are expected to further improve a.setflags(write=False)
over time. myslice = a # ERROR: requesting writable memory view from read-only buffer!
Comparison to the old buffer support Comparison to the old buffer support
......
...@@ -9,9 +9,8 @@ def new_array(): ...@@ -9,9 +9,8 @@ def new_array():
ARRAY = new_array() ARRAY = new_array()
cdef getmax(double[:] x): cdef getmax(const double[:] x):
"""Example code, should work with both """Example code, should work with both ro and rw memoryviews"""
ro and rw memoryviews"""
cdef double max_val = -float('inf') cdef double max_val = -float('inf')
for val in x: for val in x:
if val > max_val: if val > max_val:
...@@ -25,7 +24,7 @@ cdef update_array(double [:] x): ...@@ -25,7 +24,7 @@ cdef update_array(double [:] x):
cdef getconst(const double [:] x): cdef getconst(const double [:] x):
"""Should only accept ro memoryviews""" """Should accept ro memoryviews"""
return x[0] return x[0]
......
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