From eaa5f9a67859aa462fc88384e6d3bacb9c262963 Mon Sep 17 00:00:00 2001 From: LoongT4o Date: Wed, 17 May 2023 19:31:31 -0700 Subject: [PATCH] Fix the JIT buffer relocation failure at the corner case MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoids missing possible candidates due to the large address range of the free segment. Eg,  48000000-49400000 r-xs 08000000 00:0f 39322841               segment1 7ffff2ec8000-7ffff2f49000 rw-p 00000000 00:00 0              segment2 7ffff6fae000-7ffff735c000 r-xp 00200000 08:02 11538515       /usr/local/sbin/php-fpm original code will miss the opportunity between [7ffff2ec** - 7ffff2ec8000]. Fix issue #11265. Signed-off-by: Long, Tao --- ext/opcache/shared_alloc_mmap.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index 1414ef96149d0..05b6a00a7a905 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -52,11 +52,13 @@ static void *find_prefered_mmap_base(size_t requested_size) { size_t huge_page_size = 2 * 1024 * 1024; - uintptr_t last_free_addr = 0; uintptr_t last_candidate = (uintptr_t)MAP_FAILED; uintptr_t start, end, text_start = 0; + #if defined(__linux__) FILE *f; + uintptr_t last_candidate_end = 0; + uintptr_t pre_seg_end = 0; char buffer[MAXPATHLEN]; f = fopen("/proc/self/maps", "r"); @@ -67,8 +69,9 @@ static void *find_prefered_mmap_base(size_t requested_size) while (fgets(buffer, MAXPATHLEN, f) && sscanf(buffer, "%lx-%lx", &start, &end) == 2) { if ((uintptr_t)execute_ex >= start) { /* the current segment lays before PHP .text segment or PHP .text segment itself */ - if (last_free_addr + requested_size <= start) { - last_candidate = last_free_addr; + if (start - pre_seg_end >= requested_size + huge_page_size) { + last_candidate = start - requested_size - huge_page_size; + last_candidate = ZEND_MM_ALIGNED_SIZE_EX(last_candidate, huge_page_size); } if ((uintptr_t)execute_ex < end) { /* the current segment is PHP .text segment itself */ @@ -83,20 +86,22 @@ static void *find_prefered_mmap_base(size_t requested_size) } } else { /* the current segment lays after PHP .text segment */ - if (last_free_addr + requested_size - text_start > UINT32_MAX) { + last_candidate_end = pre_seg_end + requested_size + huge_page_size; + if (last_candidate_end - text_start > UINT32_MAX) { /* the current segment and the following segments lay too far from PHP .text segment */ break; } - if (last_free_addr + requested_size <= start) { - last_candidate = last_free_addr; + if (last_candidate_end <= start) { + last_candidate = ZEND_MM_ALIGNED_SIZE_EX(pre_seg_end, huge_page_size); break; } } - last_free_addr = ZEND_MM_ALIGNED_SIZE_EX(end, huge_page_size); + pre_seg_end = end; } fclose(f); #elif defined(__FreeBSD__) + uintptr_t last_free_addr = 0; size_t s = 0; int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()}; if (sysctl(mib, 4, NULL, &s, NULL, 0) == 0) {