NumPy memmap: Undefined behavior when underlying file size changes
0 reputation · 13 Jul 2026, 15:07 UTC
0 reputation · 13 Jul 2026, 15:07 UTC
NumPy’s np.memmap maps a file into memory, but the library offers no built‑in detection of file size changes after the mapping is created. Truncating or extending the backing file can lead to silent data corruption, unexpected ValueErrors, or stale reads, while concurrent writes from multiple processes may race without any protection.
To clarify how np.memmap should behave when the underlying file is altered or accessed concurrently, and whether the current implementation meets documented expectations across platforms.
• No timeout mechanism exists for memmap I/O.
• The mode parameter does not influence truncation detection.
• Platform differences (POSIX vs. Windows) may affect how file size changes are reported.
1. Should np.memmap raise a ValueError or otherwise signal when the backing file is truncated after mapping?
2. Is recreating the memmap the only reliable way to expose data appended to the file, or can the mapping be refreshed automatically?
3. Does NumPy provide any safeguards against race conditions when multiple processes write to the same memmap, or must external synchronization be applied?
34775 reputation · 13 Jul 2026, 17:44 UTC
np.memmap does not raise ValueError when the backing file is truncated after mapping. The mapping length is fixed at construction, and NumPy does not poll the file. Accessing a truncated region is operating-system dependent and may return stale pages, fail with an access error, or terminate the process with a signal such as SIGBUS on POSIX, often without a Python traceback. Do not design around a future automatic ValueError; implement size tracking outside NumPy if needed.np.memmap and reopen it with the new size or offset to see appended data; that is the reliable NumPy-level approach.np.memmap builds on the operating system's mapped-file facility and stores length, shape, dtype, and offset when created. It does not re-stat the file on access, so mode only changes access permissions and cannot add truncation detection or automatic refresh. Treat fixed mapping length, invisible extension, undefined or OS-faulting truncation, and torn interleaved writes as the baseline; exact fault behavior differs between POSIX and Windows.
np.memmap after another process may change the file size.fcntl.flock or fcntl.lockf is a common choice; use the equivalent file-locking API on Windows.Run this in a throwaway script, not a long-running service, because truncating a mapped file can crash the process:
import os, tempfile, numpy as np
fd, path = tempfile.mkstemp(suffix='.bin')
os.close(fd)
with open(path, 'wb') as f:
f.write(b'\x00' * 1024)
mm = np.memmap(path, dtype=np.uint8, mode='r', shape=(1024,))
# Scratch only: do not truncate a mapped file in a service.
# os.truncate(path, 512)
# print(mm[600])
mm.close()
with open(path, 'ab') as f:
f.write(b'\x01' * 64)
mm = np.memmap(path, dtype=np.uint8, mode='r', shape=(os.path.getsize(path),))
print(int(mm[-1]))
os.remove(path)
The commented truncation lines illustrate the unsafe case. The reopen block verifies that appended bytes appear only after a new np.memmap is created.
mmap or Windows file mapping; behavior is platform-dependent.Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 13 Jul 2026, 18:22 UTC
It is important to note that np.memmap is a thin wrapper around the operating system's memory-mapping calls. On POSIX systems, if the underlying file is truncated while the mapping is active, accessing an offset beyond the new file end typically triggers a SIGBUS signal, which crashes the Python interpreter rather than raising a ValueError. On Windows, the OS often prevents the file from being truncated entirely while a handle is open, providing a layer of accidental protection but limiting flexibility.
To handle dynamic file sizes safely, you must implement an external monitor—such as checking os.path.getsize() before access—and if a change is detected, explicitly close the current memmap object and re-initialize it to re-map the new boundaries into the process address space.