oracle / graalpython

A Python 3 implementation built on GraalVM
Other
1.2k stars 103 forks source link

Overwritten mmap files triggers a segfault #314

Closed xiaxinmeng closed 1 year ago

xiaxinmeng commented 1 year ago

See the following example. We access a mmap file, but this file is overwritten. graalpython reports a segfault

test.py

import mmap
if __name__ == '__main__':
    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  
    mm[2]

Error message:

......
Native image heap boundaries:
  ReadOnly Primitives: 0x00007fc084401028 - 0x00007fc086874298
  ReadOnly References: 0x00007fc086874298 - 0x00007fc087eaf340
  ReadOnly Relocatables: 0x00007fc087eb0000 - 0x00007fc08884da90
  Writable Primitives: 0x00007fc08884e000 - 0x00007fc08919ec18
  Writable References: 0x00007fc08919ec18 - 0x00007fc08bbc6aa8
  Writable Huge: 0x00007fc08bc00030 - 0x00007fc08bee16a8
  ReadOnly Huge: 0x00007fc08bee2030 - 0x00007fc090a6a7f0

Heap:
  Young generation: 
    Eden: 
      edenSpace:
        aligned: 0/0 unaligned: 0/0
    Survivors: 
      Survivor-1 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-1 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-2 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-2 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-3 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-3 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-4 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-4 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-5 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-5 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-6 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-6 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-7 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-7 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-8 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-8 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-9 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-9 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-10 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-10 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-11 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-11 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-12 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-12 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-13 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-13 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-14 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-14 To:
        aligned: 0/0 unaligned: 0/0
      Survivor-15 From:
        aligned: 0/0 unaligned: 0/0
      Survivor-15 To:
        aligned: 0/0 unaligned: 0/0
  Old generation: 
    oldFromSpace:
      aligned: 0/0 unaligned: 0/0
    oldToSpace:
      aligned: 0/0 unaligned: 0/0

  Unused:
    aligned: 0/0

Segfault detected, aborting process. Use runtime option -R:-InstallSegfaultHandler if you don't want to use SubstrateSegfaultHandler.

Environment: 'graalpy-22.3.1-linux-amd64/bin/graalpy' Python 3.8.5 [Graal, GraalVM CE, Java 19.0.2] on Ubuntu 18.04

msimacek commented 1 year ago

If you overwrite the contents of the file, it gets propagated to the mapping and your mm[2] is indeed invalid memory access. I get a segfault even with CPython. If you really want to write different contents to the file and keep the mapping pointing to the old one, os.unlink the old one before writing the new one:

import mmap
import os
if __name__ == '__main__':
    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)
    os.unlink('test.dat')
    with open('test.dat', 'wb') as fh:
        pass  
    mm[2]