Skip to content

Commit 048e0ea

Browse files
committed
Fix zend_alloc aligned allocation on Windows - cherrypick 9721
1 parent ad13fd5 commit 048e0ea

File tree

1 file changed

+63
-44
lines changed

1 file changed

+63
-44
lines changed

Zend/zend_alloc.c

Lines changed: 63 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,49 @@ stderr_last_error(char *msg)
416416
/* OS Allocation */
417417
/*****************/
418418

419+
static void zend_mm_munmap(void *addr, size_t size)
420+
{
421+
#ifdef _WIN32
422+
MEMORY_BASIC_INFORMATION mbi;
423+
if (VirtualQuery(addr, &mbi, sizeof(mbi)) == 0) {
424+
#if ZEND_MM_ERROR
425+
stderr_last_error("VirtualQuery() failed");
426+
#endif
427+
}
428+
addr = mbi.AllocationBase;
429+
430+
if (VirtualFree(addr, 0, MEM_RELEASE) == 0) {
431+
#if ZEND_MM_ERROR
432+
stderr_last_error("VirtualFree() failed");
433+
#endif
434+
}
435+
#else
436+
if (munmap(addr, size) != 0) {
437+
#if ZEND_MM_ERROR
438+
fprintf(stderr, "\nmunmap() failed: [%d] %s\n", errno, strerror(errno));
439+
#endif
440+
}
441+
#endif
442+
}
443+
419444
#ifndef HAVE_MREMAP
420445
static void *zend_mm_mmap_fixed(void *addr, size_t size)
421446
{
422447
#ifdef _WIN32
423-
return VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
448+
void *ptr = VirtualAlloc(addr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
449+
450+
if (ptr == NULL) {
451+
/** ERROR_INVALID_ADDRESS is expected when fixed addr range is not free */
452+
if (GetLastError() != ERROR_INVALID_ADDRESS) {
453+
#if ZEND_MM_ERROR
454+
stderr_last_error("VirtualAlloc() fixed failed");
455+
#endif
456+
}
457+
SetLastError(0);
458+
return NULL;
459+
}
460+
ZEND_ASSERT(ptr == addr);
461+
return ptr;
424462
#else
425463
int flags = MAP_PRIVATE | MAP_ANON;
426464
#if defined(MAP_EXCL)
@@ -431,15 +469,11 @@ static void *zend_mm_mmap_fixed(void *addr, size_t size)
431469

432470
if (ptr == MAP_FAILED) {
433471
#if ZEND_MM_ERROR && !defined(MAP_EXCL)
434-
fprintf(stderr, "\nmmap() failed: [%d] %s\n", errno, strerror(errno));
472+
fprintf(stderr, "\nmmap() fixed failed: [%d] %s\n", errno, strerror(errno));
435473
#endif
436474
return NULL;
437475
} else if (ptr != addr) {
438-
if (munmap(ptr, size) != 0) {
439-
#if ZEND_MM_ERROR
440-
fprintf(stderr, "\nmunmap() failed: [%d] %s\n", errno, strerror(errno));
441-
#endif
442-
}
476+
zend_mm_munmap(ptr, size);
443477
return NULL;
444478
}
445479
return ptr;
@@ -483,23 +517,6 @@ static void *zend_mm_mmap(size_t size)
483517
#endif
484518
}
485519

486-
static void zend_mm_munmap(void *addr, size_t size)
487-
{
488-
#ifdef _WIN32
489-
if (VirtualFree(addr, 0, MEM_RELEASE) == 0) {
490-
#if ZEND_MM_ERROR
491-
stderr_last_error("VirtualFree() failed");
492-
#endif
493-
}
494-
#else
495-
if (munmap(addr, size) != 0) {
496-
#if ZEND_MM_ERROR
497-
fprintf(stderr, "\nmunmap() failed: [%d] %s\n", errno, strerror(errno));
498-
#endif
499-
}
500-
#endif
501-
}
502-
503520
/***********/
504521
/* Bitmask */
505522
/***********/
@@ -682,14 +699,28 @@ static void *zend_mm_chunk_alloc_int(size_t size, size_t alignment)
682699
zend_mm_munmap(ptr, size);
683700
ptr = zend_mm_mmap(size + alignment - REAL_PAGE_SIZE);
684701
#ifdef _WIN32
685-
offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
686-
zend_mm_munmap(ptr, size + alignment - REAL_PAGE_SIZE);
687-
ptr = zend_mm_mmap_fixed((void*)((char*)ptr + (alignment - offset)), size);
688702
offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
689703
if (offset != 0) {
690-
zend_mm_munmap(ptr, size);
691-
return NULL;
704+
offset = alignment - offset;
692705
}
706+
zend_mm_munmap(ptr, size + alignment - REAL_PAGE_SIZE);
707+
ptr = zend_mm_mmap_fixed((void*)((char*)ptr + offset), size);
708+
if (ptr == NULL) { // fix GH-9650, fixed addr range is not free
709+
ptr = zend_mm_mmap(size + alignment - REAL_PAGE_SIZE);
710+
if (ptr == NULL) {
711+
return NULL;
712+
}
713+
offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
714+
if (offset != 0) {
715+
ptr = (void*)((char*)ptr + alignment - offset);
716+
}
717+
} else {
718+
offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
719+
if (offset != 0) {
720+
zend_mm_munmap(ptr, size);
721+
return NULL;
722+
}
723+
}
693724
return ptr;
694725
#else
695726
offset = ZEND_MM_ALIGNED_OFFSET(ptr, alignment);
@@ -1847,11 +1878,7 @@ static zend_mm_heap *zend_mm_init(void)
18471878

18481879
if (UNEXPECTED(chunk == NULL)) {
18491880
#if ZEND_MM_ERROR
1850-
#ifdef _WIN32
1851-
stderr_last_error("Can't initialize heap");
1852-
#else
1853-
fprintf(stderr, "\nCan't initialize heap: [%d] %s\n", errno, strerror(errno));
1854-
#endif
1881+
fprintf(stderr, "Can't initialize heap\n");
18551882
#endif
18561883
return NULL;
18571884
}
@@ -2978,11 +3005,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
29783005
chunk = (zend_mm_chunk*)handlers->chunk_alloc(&tmp_storage, ZEND_MM_CHUNK_SIZE, ZEND_MM_CHUNK_SIZE);
29793006
if (UNEXPECTED(chunk == NULL)) {
29803007
#if ZEND_MM_ERROR
2981-
#ifdef _WIN32
2982-
stderr_last_error("Can't initialize heap");
2983-
#else
2984-
fprintf(stderr, "\nCan't initialize heap: [%d] %s\n", errno, strerror(errno));
2985-
#endif
3008+
fprintf(stderr, "Can't initialize heap\n");
29863009
#endif
29873010
return NULL;
29883011
}
@@ -3025,11 +3048,7 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
30253048
if (!storage) {
30263049
handlers->chunk_free(&tmp_storage, chunk, ZEND_MM_CHUNK_SIZE);
30273050
#if ZEND_MM_ERROR
3028-
#ifdef _WIN32
3029-
stderr_last_error("Can't initialize heap");
3030-
#else
3031-
fprintf(stderr, "\nCan't initialize heap: [%d] %s\n", errno, strerror(errno));
3032-
#endif
3051+
fprintf(stderr, "Can't initialize heap\n");
30333052
#endif
30343053
return NULL;
30353054
}

0 commit comments

Comments
 (0)