Skip to content

accessing mmap of file that is overwritten causes bus error #84897

Description

@mhvk
mannequin
BPO 40720
Nosy @ronaldoussoren, @graingert, @mhvk, @iritkatriel

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2020-05-21.21:32:53.071>
labels = ['3.10', 'library', '3.9', 'type-crash', '3.11']
title = 'accessing mmap of file that is overwritten causes bus error'
updated_at = <Date 2021-10-18.22:07:24.553>
user = 'https://github.com/mhvk'

bugs.python.org fields:

activity = <Date 2021-10-18.22:07:24.553>
actor = 'iritkatriel'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Library (Lib)']
creation = <Date 2020-05-21.21:32:53.071>
creator = 'mhvk'
dependencies = []
files = []
hgrepos = []
issue_num = 40720
keywords = []
message_count = 5.0
messages = ['369543', '369635', '388337', '388339', '404230']
nosy_count = 4.0
nosy_names = ['ronaldoussoren', 'graingert', 'mhvk', 'iritkatriel']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = 'crash'
url = 'https://bugs.python.org/issue40720'
versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']

Activity

  1. mhvk commented on May 21, 2020

    mhvkmannequin
    MannequinAuthor

    While debugging a strange failure with tests and np.memmap, I realized that the following direct use of mmap reliably leads to a bus error. Here, obviously mmap'ing a file, closing it, opening the file for writing but not writing anything, and then again accessing the mmap is not something one should do (but a test case did it anyway), but it would nevertheless be nice to avoid a crash!

    import mmap
    
    
    with open('test.dat', 'wb') as fh:
        fh.write(b'abcdefghijklmnopqrstuvwxyz')
    
    
    with open('test.dat', 'rb') as fh:
        mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ)
    
    
    with open('test.dat', 'wb') as fh:
        pass  # Note: if something is written, then I get no bus error.
    
    
    mm[2]
    
  2. added
    stdlibStandard Library Python modules in the Lib/ directory
    type-crashA hard crash of the interpreter, possibly with a core dump
    on May 21, 2020
  3. mhvk commented on May 22, 2020

    mhvkmannequin
    MannequinAuthor

    I should probably have added that the bus error happens on linux. On Windows, the opening of the file for writing leads to an error, as the file is still opened for reading inside the mmap.

  4. graingert commented on Mar 9, 2021

    graingertmannequin
    Mannequin

    I can confirm this happens on py3.5-3.10

    import mmap
    import pathlib
    import tempfile
    
    
    def main():
        with tempfile.TemporaryDirectory() as tmp:
            tmp_path = pathlib.Path(tmp)
            path = tmp_path / "eg"
    
            path.write_bytes(b"Hello, World!")
    
            with path.open("rb") as rf:
                mm = mmap.mmap(rf.fileno(), 0, mmap.MAP_SHARED, mmap.PROT_READ)
                path.write_bytes(b"")
                bytes(mm)
    
    if __name__ == "__main__":
        main()
    
  5. ronaldoussoren commented on Mar 9, 2021

    @ronaldoussoren
    Contributor

    What happens here is that the file is truncated, which (more or less) truncates the memory mapping. Accessing a memory mapping beyond the length of the file results in a SIGBUS signal.

    I'm not sure if there is much Python can do about this other than shrinking the window for crashes like this by aggressively checking if the file size has changed (but even then a crash will happen if another proces truncates the file between the time the check is done and the memory is actually accessed).

    ---

    Variant of the script that explicitly truncates the file:

    def main():
        with tempfile.TemporaryDirectory() as tmp:
            tmp_path = pathlib.Path(tmp)
            path = tmp_path / "eg"
    
            path.write_bytes(b"Hello, World!")
    
            with path.open("r+b") as rf:
                mm = mmap.mmap(rf.fileno(), 0, mmap.MAP_SHARED, mmap.PROT_READ)
                rf.truncate(0)
                bytes(mm)
    
    if __name__ == "__main__":
        main()
  6. iritkatriel commented on Oct 18, 2021

    @iritkatriel
    Member

    Reproduced on 3.11.

  7. added
    3.11only security fixes
    and removed on Oct 18, 2021
  8. transferred this issue fromon Apr 10, 2022
  9. iritkatriel commented on Mar 1, 2023

    @iritkatriel
    Member

    I think this is a duplicate of #60416.
    cc @terryjreedy.

  10. ronaldoussoren commented on Mar 1, 2023

    @ronaldoussoren
    Contributor

    I agree.

    The other issue mentions that we cannot avoid this crash on our end due to limitations in the underlying APIs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.10 (EOL)end of life3.11only security fixes3.9 (EOL)end of lifestdlibStandard Library Python modules in the Lib/ directorytype-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions