From f528845993daae37a56061b8f662177ea48fc170 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Mon, 23 Sep 2013 15:02:28 -0400 Subject: [PATCH] Bug 916923 - work around crash reporter issues with adjacent memory mappings on x86 android; r=glandium,f=gbrown --- mozglue/linker/Mappable.cpp | 42 ++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/mozglue/linker/Mappable.cpp b/mozglue/linker/Mappable.cpp index c64d4073238..bd7e992e4de 100644 --- a/mozglue/linker/Mappable.cpp +++ b/mozglue/linker/Mappable.cpp @@ -183,20 +183,34 @@ public: return NULL; /* The Gecko crash reporter is confused by adjacent memory mappings of - * the same file. On Android, subsequent mappings are growing in memory - * address, and chances are we're going to map from the same file + * the same file and chances are we're going to map from the same file * descriptor right away. To avoid problems with the crash reporter, - * create an empty anonymous page after the ashmem mapping. To do so, - * allocate one page more than requested, then replace the last page with - * an anonymous mapping. */ - void *buf = ::mmap(NULL, length + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + * create an empty anonymous page before and after the ashmem mapping. + * We create two anonymous pages because on some platforms, subsequent + * mappings are placed at adjacent, increasing memory addresses (ARM) + * and on others, such mappings are placed at adjacent, decreasing + * memory addresses (x86). It is more convenient to just do two pages + * everywhere than to twiddle with platform-specific #defines. + */ + size_t anon_mapping_length = length + 2 * PAGE_SIZE; + void *buf = ::mmap(NULL, anon_mapping_length, PROT_NONE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (buf != MAP_FAILED) { - ::mmap(reinterpret_cast(buf) + ((length + PAGE_SIZE - 1) & PAGE_MASK), - PAGE_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); - DEBUG_LOG("Decompression buffer of size %d in ashmem \"%s\", mapped @%p", - length, str, buf); - return new _MappableBuffer(fd.forget(), buf, length); + char *first_page = reinterpret_cast(buf); + char *map_page = first_page + PAGE_SIZE; + char *last_page = map_page + ((length + PAGE_SIZE - 1) & PAGE_MASK); + + void *actual_buf = ::mmap(map_page, last_page - map_page, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd, 0); + if (actual_buf == MAP_FAILED) { + ::munmap(buf, anon_mapping_length); + DEBUG_LOG("Fixed allocation of decompression buffer at %p failed", map_page); + return NULL; + } + + DEBUG_LOG("Decompression buffer of size 0x%x in ashmem \"%s\", mapped @%p", + length, str, actual_buf); + return new _MappableBuffer(fd.forget(), actual_buf, length); } #else /* On Linux, use /dev/shm as base directory for temporary files, assuming @@ -236,8 +250,8 @@ public: #ifdef ANDROID ~_MappableBuffer() { - /* Free the additional page we allocated. See _MappableBuffer::Create */ - ::munmap(*this + ((GetLength() + PAGE_SIZE - 1) & PAGE_MASK), PAGE_SIZE); + /* Free the additional pages we allocated. See _MappableBuffer::Create */ + ::munmap(*this - PAGE_SIZE, GetLength() + 2 * PAGE_SIZE); } #endif