<p dir="auto"><em>Original ticket <a href="http://projects.scipy.org/numpy/ticket/2151" rel="nofollow">http://projects.scipy.org/numpy/ticket/2151</a> on 2012-06-06 by trac user tux, assigned to unknown.</em></p>
<p dir="auto">I found out that numpy.flatiter objects do not retain the base object's writeable flag. While this only leads to unexpected behavior for normal non-writeable arrays, this causes a segfault if the array's buffer is a read-only memory area (e.g. mmap).</p>
<p dir="auto">crashme1.py shows one part of the problem. The array b is created with the mmaped array a as its base. The current code creates a copy and sets the UPDATEIFCOPY flag if a is not C_CONTIGUOUS (I used Fortran order here). Now when b is destroyed it tries to write to its base (UPDATEIFCOPY) which causes a segfault because the buffer is a read-only mmap.</p>
<p dir="auto">I tried to fix this problem by only setting updateifcopy only if the original array is writeable. If not, the flatiter should be non-writeable as well in my opinion to prevent people from trying to change the original array with it which would not work. I'm not perfectly sure that I got the semantics of iter_array(iterators.c) right. Somebody with more insight into numpy should judge. At least the comment of iter_array should also be updated to reflect the new situation.</p>
<p dir="auto">After I implemented this, stumbled on another bug. Even if the flatiter is non-writeable, the function array_flat_set(getset.c) does not actually check the flag before writing to the array. This is demonstrated in the example write_the_unwriteable.py. If the non-writeable array is a read-only memory area, we get a segfault again (see crashme2.py).</p>
<p dir="auto">To fix this I added a check for the writeable flag at the beginning of array_flat_set which throws an appropriate exception (the same that direct assignment would cause).</p>
<p dir="auto">I tested all of the above on Debian Sid (Python 2.7.3 and numpy 1.6.2), Ubuntu Precise (Python 2.7.3 and numpy 1.6.1) and a self-compiled version of Python 2.7.1 and numpy 1.6.1. I could also reproduce it with python 3.2.</p>
<p dir="auto">I attached my patches against the current git HEAD to this report.</p>
<p dir="auto"><em>Original ticket <a href="http://projects.scipy.org/numpy/ticket/2148" rel="nofollow">http://projects.scipy.org/numpy/ticket/2148</a> on 2012-05-31 by trac user farrowch, assigned to unknown.</em></p>
<p dir="auto">The following code crashes on numpy 1.6.1, on OSX 10.6.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="import numpy as np
shape = (8, 8)
dtype = np.dtype(np.uint8)
image = np.random.randint(0, 256, shape).astype(dtype)
image.tofile(&quot;test_image.bin&quot;)
image = np.memmap(&quot;test_image.bin&quot;, dtype=dtype, shape=shape, mode='r')
arr = image[::2,::2]
np.sum(arr.flat)"><pre class="notranslate"><code class="notranslate">import numpy as np
shape = (8, 8)
dtype = np.dtype(np.uint8)
image = np.random.randint(0, 256, shape).astype(dtype)
image.tofile("test_image.bin")
image = np.memmap("test_image.bin", dtype=dtype, shape=shape, mode='r')
arr = image[::2,::2]
np.sum(arr.flat)
</code></pre></div>
<p dir="auto">Here's what I've discovered so far about this:</p>
<ul dir="auto">
<li>the bus error only occurs with mode 'r'</li>
<li>the dimensionality of the array appears to be irrelevant</li>
<li>if the array slice does not change the strides, the bus error does not occur</li>
<li>no 'arr.flat', no bus error</li>
<li>Other aggregating functions (e.g. fmin.reduce) will induce the error</li>
<li>Iterating over arr.flat will <em>not</em> cause a bus error</li>
</ul>
<p dir="auto">Based on this, I suspect the issue is with the C-facing side of the flat iterator.</p>