]> granicus.if.org Git - php/commitdiff
Fixed bug #75368 (mmap/munmap trashing on unlucky allocations)
authorDmitry Stogov <dmitry@zend.com>
Fri, 13 Oct 2017 10:56:06 +0000 (13:56 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 13 Oct 2017 10:56:06 +0000 (13:56 +0300)
NEWS
Zend/zend_alloc.c

diff --git a/NEWS b/NEWS
index daa50266c13c6642a10c51bdd496108136d28808..11223dd97a5ee05d9a061a0b48c417e908370607 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,10 @@ PHP                                                                        NEWS
 |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
 ?? ??? 2017 PHP 7.0.26
 
+- Core:
+  . Fixed bug #75368 (mmap/munmap trashing on unlucky allocations). (Nikita,
+    Dmitry)
+
 - Exif:
   . Fixed bug #75301 (Exif extension has built in revision version). (Peter
     Kokot)
index 48def78a41dc0e8f0f01bc18a0a16949b08b8422..be41aa3e4ab0e281f4d57beffa72780223defbc0 100644 (file)
@@ -267,6 +267,8 @@ struct _zend_mm_heap {
        int                peak_chunks_count;           /* peak number of allocated chunks for current request */
        int                cached_chunks_count;         /* number of cached chunks */
        double             avg_chunks_count;            /* average number of chunks allocated per request */
+       int                last_chunks_delete_boundary; /* numer of chunks after last deletion */
+       int                last_chunks_delete_count;    /* number of deletion over the last boundary */
 #if ZEND_MM_CUSTOM
        union {
                struct {
@@ -1122,7 +1124,9 @@ static zend_always_inline void zend_mm_delete_chunk(zend_mm_heap *heap, zend_mm_
        chunk->next->prev = chunk->prev;
        chunk->prev->next = chunk->next;
        heap->chunks_count--;
-       if (heap->chunks_count + heap->cached_chunks_count < heap->avg_chunks_count + 0.1) {
+       if (heap->chunks_count + heap->cached_chunks_count < heap->avg_chunks_count + 0.1
+        || (heap->chunks_count == heap->last_chunks_delete_boundary
+         && heap->last_chunks_delete_count >= 4)) {
                /* delay deletion */
                heap->cached_chunks_count++;
                chunk->next = heap->cached_chunks;
@@ -1131,6 +1135,14 @@ static zend_always_inline void zend_mm_delete_chunk(zend_mm_heap *heap, zend_mm_
 #if ZEND_MM_STAT || ZEND_MM_LIMIT
                heap->real_size -= ZEND_MM_CHUNK_SIZE;
 #endif
+               if (!heap->cached_chunks) {
+                       if (heap->chunks_count != heap->last_chunks_delete_boundary) {
+                               heap->last_chunks_delete_boundary = heap->chunks_count;
+                               heap->last_chunks_delete_count = 0;
+                       } else {
+                               heap->last_chunks_delete_count++;
+                       }
+               }
                if (!heap->cached_chunks || chunk->num > heap->cached_chunks->num) {
                        zend_mm_chunk_free(heap, chunk, ZEND_MM_CHUNK_SIZE);
                } else {
@@ -1864,6 +1876,8 @@ static zend_mm_heap *zend_mm_init(void)
        heap->peak_chunks_count = 1;
        heap->cached_chunks_count = 0;
        heap->avg_chunks_count = 1.0;
+       heap->last_chunks_delete_boundary = 0;
+       heap->last_chunks_delete_count = 0;
 #if ZEND_MM_STAT || ZEND_MM_LIMIT
        heap->real_size = ZEND_MM_CHUNK_SIZE;
 #endif
@@ -2279,6 +2293,8 @@ void zend_mm_shutdown(zend_mm_heap *heap, int full, int silent)
                p->map[0] = ZEND_MM_LRUN(ZEND_MM_FIRST_PAGE);
                heap->chunks_count = 1;
                heap->peak_chunks_count = 1;
+               heap->last_chunks_delete_boundary = 0;
+               heap->last_chunks_delete_count = 0;
 #if ZEND_MM_STAT || ZEND_MM_LIMIT
                heap->real_size = ZEND_MM_CHUNK_SIZE;
 #endif
@@ -2811,6 +2827,8 @@ ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_handlers *handlers, void
        heap->peak_chunks_count = 1;
        heap->cached_chunks_count = 0;
        heap->avg_chunks_count = 1.0;
+       heap->last_chunks_delete_boundary = 0;
+       heap->last_chunks_delete_count = 0;
 #if ZEND_MM_STAT || ZEND_MM_LIMIT
        heap->real_size = ZEND_MM_CHUNK_SIZE;
 #endif