diff --git a/ext/opcache/shared_alloc_mmap.c b/ext/opcache/shared_alloc_mmap.c index d3a5916be89b3..cd6803df6481b 100644 --- a/ext/opcache/shared_alloc_mmap.c +++ b/ext/opcache/shared_alloc_mmap.c @@ -66,13 +66,21 @@ static void *find_prefered_mmap_base(size_t requested_size) * a segment directly preceding or following the heap is interpreted as heap memory, which * will result in an execheap violation for the JIT. * See https://bugzilla.kernel.org/show_bug.cgi?id=218258. */ + /* Also don't place the segment too close to the end of the heap, as + * this can prevent it from expanding contiguously, which may confuse + * some code (GH-13775). */ bool heap_segment = strstr(buffer, "[heap]") != NULL; if (heap_segment) { - uintptr_t start_base = start & ~(huge_page_size - 1); - if (last_free_addr + requested_size >= start_base) { - last_free_addr = ZEND_MM_ALIGNED_SIZE_EX(end + huge_page_size, huge_page_size); - continue; + if (last_candidate != (uintptr_t)MAP_FAILED) { + uintptr_t start_base = start & ~(huge_page_size - 1); + if (last_free_addr + requested_size >= start_base) { + last_candidate = (uintptr_t)MAP_FAILED; + } } + /* The heap is located after the text segment, so once we find it + * there is no chance of finding a better candidate that is close + * enough of the text segment and also far enough from the heap. */ + break; } if ((uintptr_t)execute_ex >= start) { /* the current segment lays before PHP .text segment or PHP .text segment itself */