<p dir="auto">I'm not 100% sure if this is a numpy or python bug, but the behavior is quite weird. I've narrowed it down to two simple test cases, one which works and one which segfaults.</p>
<p dir="auto">I can create a SharedMemory object, I can create a numpy array backed by it and read and write to it. I can do the same with a second SharedMemory object referring to the same space, created using the name. But I can't have a function return this np array, or accesses will segfault.</p>
<h3 dir="auto">Reproducing code example:</h3>

<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from multiprocessing import shared_memory
import numpy as np

def np_array_from_shm_name(name, shape=(2,)):
    shm = shared_memory.SharedMemory(name=name)
    np_array = np.ndarray(shape, buffer=shm.buf, dtype=np.int32)
    np_array[:] = (0,0)
    print(np_array)  # prints [0 0]
    return np_array


if __name__ == &quot;__main__&quot;:
    shm = shared_memory.SharedMemory(create=True, size=8)
    shm2 = shared_memory.SharedMemory(name=shm.name)
    np_array = np.ndarray((2,), buffer=shm.buf, dtype=np.int32)
    np_array[:] = (0, 0)
    print(np_array)  # prints [0 0]
    np_array = np.ndarray((2,), buffer=shm2.buf, dtype=np.int32)
    np_array[:] = (0, 0)
    print(np_array)  # prints [0 0]
    np_array = np_array_from_shm_name(shm.name)
    np_array[:] = (0, 0)  # segfaults
    print(np_array)
    shm.unlink()
    shm2.unlink()"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">multiprocessing</span> <span class="pl-k">import</span> <span class="pl-s1">shared_memory</span>
<span class="pl-k">import</span> <span class="pl-s1">numpy</span> <span class="pl-k">as</span> <span class="pl-s1">np</span>

<span class="pl-k">def</span> <span class="pl-en">np_array_from_shm_name</span>(<span class="pl-s1">name</span>, <span class="pl-s1">shape</span><span class="pl-c1">=</span>(<span class="pl-c1">2</span>,)):
    <span class="pl-s1">shm</span> <span class="pl-c1">=</span> <span class="pl-s1">shared_memory</span>.<span class="pl-v">SharedMemory</span>(<span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-s1">name</span>)
    <span class="pl-s1">np_array</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">ndarray</span>(<span class="pl-s1">shape</span>, <span class="pl-s1">buffer</span><span class="pl-c1">=</span><span class="pl-s1">shm</span>.<span class="pl-s1">buf</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s1">np</span>.<span class="pl-s1">int32</span>)
    <span class="pl-s1">np_array</span>[:] <span class="pl-c1">=</span> (<span class="pl-c1">0</span>,<span class="pl-c1">0</span>)
    <span class="pl-en">print</span>(<span class="pl-s1">np_array</span>)  <span class="pl-c"># prints [0 0]</span>
    <span class="pl-k">return</span> <span class="pl-s1">np_array</span>


<span class="pl-k">if</span> <span class="pl-s1">__name__</span> <span class="pl-c1">==</span> <span class="pl-s">"__main__"</span>:
    <span class="pl-s1">shm</span> <span class="pl-c1">=</span> <span class="pl-s1">shared_memory</span>.<span class="pl-v">SharedMemory</span>(<span class="pl-s1">create</span><span class="pl-c1">=</span><span class="pl-c1">True</span>, <span class="pl-s1">size</span><span class="pl-c1">=</span><span class="pl-c1">8</span>)
    <span class="pl-s1">shm2</span> <span class="pl-c1">=</span> <span class="pl-s1">shared_memory</span>.<span class="pl-v">SharedMemory</span>(<span class="pl-s1">name</span><span class="pl-c1">=</span><span class="pl-s1">shm</span>.<span class="pl-s1">name</span>)
    <span class="pl-s1">np_array</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">ndarray</span>((<span class="pl-c1">2</span>,), <span class="pl-s1">buffer</span><span class="pl-c1">=</span><span class="pl-s1">shm</span>.<span class="pl-s1">buf</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s1">np</span>.<span class="pl-s1">int32</span>)
    <span class="pl-s1">np_array</span>[:] <span class="pl-c1">=</span> (<span class="pl-c1">0</span>, <span class="pl-c1">0</span>)
    <span class="pl-en">print</span>(<span class="pl-s1">np_array</span>)  <span class="pl-c"># prints [0 0]</span>
    <span class="pl-s1">np_array</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">ndarray</span>((<span class="pl-c1">2</span>,), <span class="pl-s1">buffer</span><span class="pl-c1">=</span><span class="pl-s1">shm2</span>.<span class="pl-s1">buf</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s1">np</span>.<span class="pl-s1">int32</span>)
    <span class="pl-s1">np_array</span>[:] <span class="pl-c1">=</span> (<span class="pl-c1">0</span>, <span class="pl-c1">0</span>)
    <span class="pl-en">print</span>(<span class="pl-s1">np_array</span>)  <span class="pl-c"># prints [0 0]</span>
    <span class="pl-s1">np_array</span> <span class="pl-c1">=</span> <span class="pl-en">np_array_from_shm_name</span>(<span class="pl-s1">shm</span>.<span class="pl-s1">name</span>)
    <span class="pl-s1">np_array</span>[:] <span class="pl-c1">=</span> (<span class="pl-c1">0</span>, <span class="pl-c1">0</span>)  <span class="pl-c"># segfaults</span>
    <span class="pl-en">print</span>(<span class="pl-s1">np_array</span>)
    <span class="pl-s1">shm</span>.<span class="pl-en">unlink</span>()
    <span class="pl-s1">shm2</span>.<span class="pl-en">unlink</span>()</pre></div>
<h3 dir="auto">Error message:</h3>

<p dir="auto">Thread 1 "python3-dbg" received signal SIGSEGV, Segmentation fault.<br>
0x00007ffff692e0e9 in INT_setitem (op=0, ov=0x7ffff7491000, vap=0x7fffd68cbd60) at numpy/core/src/multiarray/arraytypes.c.src:235<br>
235	numpy/core/src/multiarray/arraytypes.c.src: No such file or directory.<br>
(gdb) py-bt<br>
Traceback (most recent call first):<br>
File "segfault_poc_simple.py", line 66, in <br>
np_array[:] = (0, 0)  # segfaults</p>

<h3 dir="auto">NumPy/Python version information:</h3>

<p dir="auto">1.17.4 3.8.6 (default, Sep 25 2020, 09:36:53)<br>
[GCC 10.2.0]</p>
<p dir="auto">This crashes in python2 and python3 with a segfault:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="import mmap

# create test file
a = arange(10., dtype='f4')
a.tofile('test')

# opens it as a memmap
with open('test', 'r+b') as f:
      mm = mmap.mmap(f.fileno(),0)

#view the mmap, then close it
x = np.frombuffer(mm, dtype='f4')
mm.close()
print(x)  # segfault"><pre class="notranslate"><span class="pl-k">import</span> <span class="pl-s1">mmap</span>

<span class="pl-c"># create test file</span>
<span class="pl-s1">a</span> <span class="pl-c1">=</span> <span class="pl-en">arange</span>(<span class="pl-c1">10.</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">'f4'</span>)
<span class="pl-s1">a</span>.<span class="pl-en">tofile</span>(<span class="pl-s">'test'</span>)

<span class="pl-c"># opens it as a memmap</span>
<span class="pl-k">with</span> <span class="pl-en">open</span>(<span class="pl-s">'test'</span>, <span class="pl-s">'r+b'</span>) <span class="pl-k">as</span> <span class="pl-s1">f</span>:
      <span class="pl-s1">mm</span> <span class="pl-c1">=</span> <span class="pl-s1">mmap</span>.<span class="pl-en">mmap</span>(<span class="pl-s1">f</span>.<span class="pl-en">fileno</span>(),<span class="pl-c1">0</span>)

<span class="pl-c">#view the mmap, then close it</span>
<span class="pl-s1">x</span> <span class="pl-c1">=</span> <span class="pl-s1">np</span>.<span class="pl-en">frombuffer</span>(<span class="pl-s1">mm</span>, <span class="pl-s1">dtype</span><span class="pl-c1">=</span><span class="pl-s">'f4'</span>)
<span class="pl-s1">mm</span>.<span class="pl-en">close</span>()
<span class="pl-en">print</span>(<span class="pl-s1">x</span>)  <span class="pl-c"># segfault</span></pre></div>
<p dir="auto">In <code class="notranslate">frombuffer</code> mumpy uses the PEP3118 interface to the mmap to get a pointer to the data, so it seems we are using the interface incorrectly somewhere.</p>
<p dir="auto">It seems to me that the "correct" behavior may be for it to be impossible to close the memmap while pointers to it exist; this is the behavior for <code class="notranslate">memoryview</code>s of mmaps. That is, the line <code class="notranslate">mm.close()</code> shoud raise an error <code class="notranslate">BufferError: cannot close exported pointers</code>, as in currently happens in python3:</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="&gt;&gt;&gt; import mmap
&gt;&gt;&gt; with open('test', 'r+b') as f:
&gt;&gt;&gt;     mm = mmap.mmap(f.fileno(),0)
&gt;&gt;&gt; mv = memoryview(mm)
&gt;&gt;&gt; mm.close()
BufferError: cannot close exported pointers exist"><pre class="notranslate"><span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-k">import</span> <span class="pl-s1">mmap</span>
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-k">with</span> <span class="pl-en">open</span>(<span class="pl-s">'test'</span>, <span class="pl-s">'r+b'</span>) <span class="pl-k">as</span> <span class="pl-s1">f</span>:
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span>     <span class="pl-s1">mm</span> <span class="pl-c1">=</span> <span class="pl-s1">mmap</span>.<span class="pl-en">mmap</span>(<span class="pl-s1">f</span>.<span class="pl-en">fileno</span>(),<span class="pl-c1">0</span>)
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">mv</span> <span class="pl-c1">=</span> <span class="pl-en">memoryview</span>(<span class="pl-s1">mm</span>)
<span class="pl-c1">&gt;&gt;</span><span class="pl-c1">&gt;</span> <span class="pl-s1">mm</span>.<span class="pl-en">close</span>()
<span class="pl-v">BufferError</span>: <span class="pl-s1">cannot</span> <span class="pl-s1">close</span> <span class="pl-s1">exported</span> <span class="pl-s1">pointers</span> <span class="pl-s1">exist</span></pre></div>
<p dir="auto">however note also that in python2 we cannot create the memoryview (<code class="notranslate">mv</code>) because of an error <code class="notranslate">TypeError: cannot make memory view because object does not have the buffer interface</code>.</p>
<p dir="auto">Note how <a href="https://github.com/python/cpython/blob/b879fe82e7e5c3f7673c9a7fa4aad42bd05445d8/Modules/mmapmodule.c#L727">mmap_buffer_getbuf (link)</a> in the mmap module takes care to keep track of any buffer access to the mmap (the <code class="notranslate">exports</code> counter). Evidently we are somehow bypassing that in numpy.</p>