summaryrefslogtreecommitdiff
path: root/disassembler/disassembler_arm.cc
diff options
context:
space:
mode:
author Hiroshi Yamauchi <yamauchi@google.com> 2013-10-22 14:17:48 -0700
committer Hiroshi Yamauchi <yamauchi@google.com> 2013-10-25 11:39:50 -0700
commitfd7e7f1253927c8d7f17e7cbc259daaf51868bd3 (patch)
tree2bc3e24751d34e561ae94b6763215e6e209e4dbb /disassembler/disassembler_arm.cc
parent8584a68279efc0f9a409a3555ae5ebf3ec2cc4ac (diff)
Fix a double unmap issue in MemMap::UnMapAtEnd().
MemMap::UnMapAtEnd() unmaps the unused tail of the alloc space during a zygote fork. But it can cause the same tail region of the memory to be unmapped twice (once in UnMapAtEnd() and once more in ~MemMap() during a shutdown.) I encountered a crash because of this issue in SpaceTest.ZygoteTest (which happens to happen only on a device in a branch with the rosalloc change probably due to some randomness in mmap address choice, etc.) Here's what happens: 1) CreateZygoteSpace() will call UnMapAtEnd() and unmap the unused tail of the alloc space. 2) In the same function, after UnMapAtEnd(), several libc new/malloc allocations, including a new DlMallocSpace object, happen. This happens to cause libc to map a new memory region that overlaps with the memory region that has just been unmapped in 1) and use it to allocate those allocations (that is, the new DlMallocSpace object is allocated in that memory region.) This is a second DlMallocSpace that becomes the new alloc space after zygote fork. The first DlMallocSpace becomes the zygote space. Note that that libc maps that memory region before the underlying memory of the second DlMallocSpace is mapped. 3) During a Runtime shutdown (which happens once for a normal VM shutdown or at the end of each test run) all the spaces get destructed including the the two DlMallocSpaces one by one. When the first DlMallocSpace gets destructed (note the space list is sorted by address,) its super destructor ~MemMap() unmaps the original memory region that's already partially unmapped in 2). Now this memory region includes the libc memory region that includes the second DlMallocSpace object. 4) When the second DlMallocSpace object gets attempted to be destructed, the memory in which the object resides is already unmapped in 3) and causes a SIGSEGV. This change replaces UnMapAtEnd() with a new function RemapAtEnd() which combines the unmapping of the tail region and remapping of it to achieve the following two things: 1) Fixes this double unmap issue by updating the base_size_ member variable to exclude the already-unmapped tail region so that ~MemMap() will not unmap the tail region again. 2) Improves on the non-atomicity issue in the unmap/map sequence in CreateZygoteSpace(). That is, once the unused tail portion of the memory region of the origina alloc space is unmapped, something like libc could come along and take that memory region, before the memory region is mapped again for the new alloc space. This, as a result, would make a hole between the old alloc (new zygote) space and the new alloc space and cause the two spaces to be non-contiguous. RemapAtEnd() eliminates new/malloc allocations between the unmap and the map calls. But note this still isn't perfect as other threads could in theory take the memory region between the munmap and the mmap calls. Added tests. Change-Id: I43bc3a33a2cbfc7a092890312e34aa5285384589
Diffstat (limited to 'disassembler/disassembler_arm.cc')
0 files changed, 0 insertions, 0 deletions