diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c index f6c0a1ad0e98..d6fc959e9c49 100644 --- a/Zend/zend_alloc.c +++ b/Zend/zend_alloc.c @@ -356,6 +356,7 @@ struct _zend_mm_huge_list { void *ptr; size_t size; zend_mm_huge_list *next; + zend_mm_huge_list *prev; #if ZEND_DEBUG zend_mm_debug_info dbg; #endif @@ -1931,6 +1932,10 @@ static void zend_mm_add_huge_block(zend_mm_heap *heap, void *ptr, size_t size ZE list->ptr = ptr; list->size = size; list->next = heap->huge_list; + list->prev = NULL; + if (heap->huge_list) { + heap->huge_list->prev = list; + } #if ZEND_DEBUG list->dbg.size = dbg_size; list->dbg.filename = __zend_filename; @@ -1943,22 +1948,28 @@ static void zend_mm_add_huge_block(zend_mm_heap *heap, void *ptr, size_t size ZE static size_t zend_mm_del_huge_block(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) { - zend_mm_huge_list *prev = NULL; zend_mm_huge_list *list = heap->huge_list; while (list != NULL) { if (list->ptr == ptr) { size_t size; - if (prev) { - prev->next = list->next; + /* Unlinking writes through these, so make sure they still point back + * at this block before trusting them. */ + ZEND_MM_CHECK(list->prev ? list->prev->next == list : heap->huge_list == list, "zend_mm_heap corrupted"); + ZEND_MM_CHECK(!list->next || list->next->prev == list, "zend_mm_heap corrupted"); + + if (list->prev) { + list->prev->next = list->next; } else { heap->huge_list = list->next; } + if (list->next) { + list->next->prev = list->prev; + } size = list->size; zend_mm_free_heap(heap, list ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); return size; } - prev = list; list = list->next; } ZEND_MM_CHECK(0, "zend_mm_heap corrupted"); @@ -2388,6 +2399,9 @@ static zend_long zend_mm_find_leaks_huge(zend_mm_heap *heap, zend_mm_huge_list * while (p) { if (p->dbg.filename == list->dbg.filename && p->dbg.lineno == list->dbg.lineno) { prev->next = p->next; + if (p->next) { + p->next->prev = prev; + } zend_mm_chunk_free(heap, p->ptr, p->size); zend_mm_free_heap(heap, p, NULL, 0, NULL, 0); count++; @@ -2430,6 +2444,9 @@ static void zend_mm_check_leaks(zend_mm_heap *heap) } heap->huge_list = list = list->next; + if (list) { + list->prev = NULL; + } zend_mm_chunk_free(heap, q->ptr, q->size); zend_mm_free_heap(heap, q, NULL, 0, NULL, 0); }