From 8d65c2fee596c337919f9de3cc69c15c3487d64d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Vo=C5=99=C3=AD=C5=A1ek?= Date: Mon, 14 Nov 2022 15:16:31 +0100 Subject: [PATCH] Fix GH-9650: Can't initialize heap: [0x000001e7] Closes GH-9721. --- NEWS | 1 + Zend/zend_alloc.c | 113 ++++++++++++++++++++++++++++------------------ 2 files changed, 70 insertions(+), 44 deletions(-) diff --git a/NEWS b/NEWS index 6ded7436a13..bde353a2488 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,7 @@ PHP NEWS (cmb) . Fixed bug GH-9918 (License information for xxHash is not included in README.REDIST.BINS file). (Akama Hitoshi) + . Fixed bug GH-9650 (Can't initialize heap: [0x000001e7]). (Michael Voříšek) - MBString: . Fixed bug GH-9535 (The behavior of mb_strcut in mbstring has been changed in diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index dfdc4e2bb4c..ae22be434fb 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -416,11 +416,61 @@ stderr_last_error(char *msg) /* OS Allocation */ /*****************/ +static void zend_mm_munmap(void *addr, size_t size) +{ +#ifdef _WIN32 + if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { + /** ERROR_INVALID_ADDRESS is expected when addr is not range start address */ + if (GetLastError() != ERROR_INVALID_ADDRESS) { +#if ZEND_MM_ERROR + stderr_last_error("VirtualFree() failed"); +#endif + return; + } + SetLastError(0); + + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery(addr, &mbi, sizeof(mbi)) == 0) { +#if ZEND_MM_ERROR + stderr_last_error("VirtualQuery() failed"); +#endif + return; + } + addr = mbi.AllocationBase; + + if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { +#if ZEND_MM_ERROR + stderr_last_error("VirtualFree() failed"); +#endif + } + } +#else + if (munmap(addr, size) != 0) { +#if ZEND_MM_ERROR + fprintf(stderr, "\nmunmap() failed: [%d] %s\n", errno, strerror(errno)); +#endif + } +#endif +} + #ifndef HAVE_MREMAP static void *zend_mm_mmap_fixed(void *addr, size_t size) { #ifdef _WIN32 - return VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + void *ptr = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + + if (ptr == NULL) { + /** ERROR_INVALID_ADDRESS is expected when fixed addr range is not free */ + if (GetLastError() != ERROR_INVALID_ADDRESS) { +#if ZEND_MM_ERROR + stderr_last_error("VirtualAlloc() fixed failed"); +#endif + } + SetLastError(0); + return NULL; + } + ZEND_ASSERT(ptr == addr); + return ptr; #else int flags = MAP_PRIVATE | MAP_ANON; #if defined(MAP_EXCL) @@ -431,15 +481,11 @@ static void *zend_mm_mmap_fixed(void *addr, size_t size) if (ptr == MAP_FAILED) { #if ZEND_MM_ERROR && !defined(MAP_EXCL) - fprintf(stderr, "\nmmap() failed: [%d] %s\n", errno, strerror(errno)); + fprintf(stderr, "\nmmap() fixed failed: [%d] %s\n", errno, strerror(errno)); #endif return NULL; } else if (ptr != addr) { - if (munmap(ptr, size) != 0) { -#if ZEND_MM_ERROR - fprintf(stderr, "\nmunmap() failed: [%d] %s\n", errno, strerror(errno)); -#endif - } + zend_mm_munmap(ptr, size); return NULL; } return ptr; @@ -483,23 +529,6 @@ static void *zend_mm_mmap(size_t size) #endif } -static void zend_mm_munmap(void *addr, size_t size) -{ -#ifdef _WIN32 - if (VirtualFree(addr, 0, MEM_RELEASE) == 0) { -#if ZEND_MM_ERROR - stderr_last_error("VirtualFree() failed"); -#endif - } -#else - if (munmap(addr, size) != 0) { -#if ZEND_MM_ERROR - fprintf(stderr, "\nmunmap() failed: [%d] %s\n", errno, strerror(errno)); -#endif - } -#endif -} - /***********/ /* Bitmask */ /***********/ @@ -682,13 +711,21 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment) zend_mm_munmap(ptr, size); ptr = zend_mm_mmap(size + alignment - REAL_PAGE_SIZE); #ifdef _WIN32 - offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment); - zend_mm_munmap(ptr, size + alignment - REAL_PAGE_SIZE); - ptr = zend_mm_mmap_fixed((void*)((char*)ptr + (alignment - offset)), size); offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment); if (offset != 0) { - zend_mm_munmap(ptr, size); - return NULL; + offset = alignment - offset; + } + zend_mm_munmap(ptr, size + alignment - REAL_PAGE_SIZE); + ptr = zend_mm_mmap_fixed((void*)((char*)ptr + offset), size); + if (ptr == NULL) { // fix GH-9650, fixed addr range is not free + ptr = zend_mm_mmap(size + alignment - REAL_PAGE_SIZE); + if (ptr == NULL) { + return NULL; + } + offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment); + if (offset != 0) { + ptr = (void*)((char*)ptr + alignment - offset); + } } return ptr; #else @@ -1847,11 +1884,7 @@ static zend_mm_heap *zend_mm_init(void) if (UNEXPECTED(chunk == NULL)) { #if ZEND_MM_ERROR -#ifdef _WIN32 - stderr_last_error("Can't initialize heap"); -#else - fprintf(stderr, "\nCan't initialize heap: [%d] %s\n", errno, strerror(errno)); -#endif + fprintf(stderr, "Can't initialize heap\n"); #endif return NULL; } @@ -2978,11 +3011,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void chunk = (zend_mm_chunk*)handlers->chunk_alloc(&tmp_storage, ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE); if (UNEXPECTED(chunk == NULL)) { #if ZEND_MM_ERROR -#ifdef _WIN32 - stderr_last_error("Can't initialize heap"); -#else - fprintf(stderr, "\nCan't initialize heap: [%d] %s\n", errno, strerror(errno)); -#endif + fprintf(stderr, "Can't initialize heap\n"); #endif return NULL; } @@ -3025,11 +3054,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void if (!storage) { handlers->chunk_free(&tmp_storage, chunk, ZEND_MM_CHUNK_SIZE); #if ZEND_MM_ERROR -#ifdef _WIN32 - stderr_last_error("Can't initialize heap"); -#else - fprintf(stderr, "\nCan't initialize heap: [%d] %s\n", errno, strerror(errno)); -#endif + fprintf(stderr, "Can't initialize heap\n"); #endif return NULL; }