PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - Zend - zend_alloc.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 462 701 65.9 %
Date: 2014-04-18 Functions: 37 56 66.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | Zend Engine                                                          |
       4             :    +----------------------------------------------------------------------+
       5             :    | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
       6             :    +----------------------------------------------------------------------+
       7             :    | This source file is subject to version 2.00 of the Zend license,     |
       8             :    | that is bundled with this package in the file LICENSE, and is        |
       9             :    | available through the world-wide-web at the following url:           |
      10             :    | http://www.zend.com/license/2_00.txt.                                |
      11             :    | If you did not receive a copy of the Zend license and are unable to  |
      12             :    | obtain it through the world-wide-web, please send a note to          |
      13             :    | license@zend.com so we can mail you a copy immediately.              |
      14             :    +----------------------------------------------------------------------+
      15             :    | Authors: Andi Gutmans <andi@zend.com>                                |
      16             :    |          Zeev Suraski <zeev@zend.com>                                |
      17             :    |          Dmitry Stogov <dmitry@zend.com>                             |
      18             :    +----------------------------------------------------------------------+
      19             : */
      20             : 
      21             : /* $Id$ */
      22             : 
      23             : #include "zend.h"
      24             : #include "zend_alloc.h"
      25             : #include "zend_globals.h"
      26             : #include "zend_operators.h"
      27             : 
      28             : #ifdef HAVE_SIGNAL_H
      29             : # include <signal.h>
      30             : #endif
      31             : #ifdef HAVE_UNISTD_H
      32             : # include <unistd.h>
      33             : #endif
      34             : 
      35             : #ifdef ZEND_WIN32
      36             : # include <wincrypt.h>
      37             : # include <process.h>
      38             : #endif
      39             : 
      40             : #ifndef ZEND_MM_HEAP_PROTECTION
      41             : # define ZEND_MM_HEAP_PROTECTION ZEND_DEBUG
      42             : #endif
      43             : 
      44             : #ifndef ZEND_MM_SAFE_UNLINKING
      45             : # define ZEND_MM_SAFE_UNLINKING 1
      46             : #endif
      47             : 
      48             : #ifndef ZEND_MM_COOKIES
      49             : # define ZEND_MM_COOKIES ZEND_DEBUG
      50             : #endif
      51             : 
      52             : #ifdef _WIN64
      53             : # define PTR_FMT "0x%0.16I64x"
      54             : /*
      55             : #elif sizeof(long) == 8
      56             : # define PTR_FMT "0x%0.16lx"
      57             : */
      58             : #else
      59             : # define PTR_FMT "0x%0.8lx"
      60             : #endif
      61             : 
      62             : #if ZEND_DEBUG
      63             : void zend_debug_alloc_output(char *format, ...)
      64             : {
      65             :         char output_buf[256];
      66             :         va_list args;
      67             : 
      68             :         va_start(args, format);
      69             :         vsprintf(output_buf, format, args);
      70             :         va_end(args);
      71             : 
      72             : #ifdef ZEND_WIN32
      73             :         OutputDebugString(output_buf);
      74             : #else
      75             :         fprintf(stderr, "%s", output_buf);
      76             : #endif
      77             : }
      78             : #endif
      79             : 
      80             : #if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
      81             : static void zend_mm_panic(const char *message) __attribute__ ((noreturn));
      82             : #endif
      83             : 
      84           0 : static void zend_mm_panic(const char *message)
      85             : {
      86           0 :         fprintf(stderr, "%s\n", message);
      87             : /* See http://support.microsoft.com/kb/190351 */
      88             : #ifdef PHP_WIN32
      89             :         fflush(stderr);
      90             : #endif
      91             : #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID)
      92             :         kill(getpid(), SIGSEGV);
      93             : #endif
      94           0 :         exit(1);
      95             : }
      96             : 
      97             : /*******************/
      98             : /* Storage Manager */
      99             : /*******************/
     100             : 
     101             : #ifdef ZEND_WIN32
     102             : #  define HAVE_MEM_WIN32    /* use VirtualAlloc() to allocate memory     */
     103             : #endif
     104             : #define HAVE_MEM_MALLOC     /* use malloc() to allocate segments         */
     105             : 
     106             : #include <sys/types.h>
     107             : #include <sys/stat.h>
     108             : #if HAVE_LIMITS_H
     109             : #include <limits.h>
     110             : #endif
     111             : #include <fcntl.h>
     112             : #include <errno.h>
     113             : 
     114             : #if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
     115             : # ifdef HAVE_MREMAP
     116             : #  ifndef _GNU_SOURCE
     117             : #   define _GNU_SOURCE
     118             : #  endif
     119             : #  ifndef __USE_GNU
     120             : #   define __USE_GNU
     121             : #  endif
     122             : # endif
     123             : # include <sys/mman.h>
     124             : # ifndef MAP_ANON
     125             : #  ifdef MAP_ANONYMOUS
     126             : #   define MAP_ANON MAP_ANONYMOUS
     127             : #  endif
     128             : # endif
     129             : # ifndef MREMAP_MAYMOVE
     130             : #  define MREMAP_MAYMOVE 0
     131             : # endif
     132             : # ifndef MAP_FAILED
     133             : #  define MAP_FAILED ((void*)-1)
     134             : # endif
     135             : #endif
     136             : 
     137       19341 : static zend_mm_storage* zend_mm_mem_dummy_init(void *params)
     138             : {
     139       19341 :         return malloc(sizeof(zend_mm_storage));
     140             : }
     141             : 
     142       19376 : static void zend_mm_mem_dummy_dtor(zend_mm_storage *storage)
     143             : {
     144       19376 :         free(storage);
     145       19376 : }
     146             : 
     147           1 : static void zend_mm_mem_dummy_compact(zend_mm_storage *storage)
     148             : {
     149           1 : }
     150             : 
     151             : #if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
     152             : 
     153           0 : static zend_mm_segment* zend_mm_mem_mmap_realloc(zend_mm_storage *storage, zend_mm_segment* segment, size_t size)
     154             : {
     155             :         zend_mm_segment *ret;
     156             : #ifdef HAVE_MREMAP
     157             : #if defined(__NetBSD__)
     158             :         /* NetBSD 5 supports mremap but takes an extra newp argument */
     159             :         ret = (zend_mm_segment*)mremap(segment, segment->size, segment, size, MREMAP_MAYMOVE);
     160             : #else
     161           0 :         ret = (zend_mm_segment*)mremap(segment, segment->size, size, MREMAP_MAYMOVE);
     162             : #endif
     163           0 :         if (ret == MAP_FAILED) {
     164             : #endif
     165           0 :                 ret = storage->handlers->_alloc(storage, size);
     166           0 :                 if (ret) {
     167           0 :                         memcpy(ret, segment, size > segment->size ? segment->size : size);
     168           0 :                         storage->handlers->_free(storage, segment);
     169             :                 }
     170             : #ifdef HAVE_MREMAP
     171             :         }
     172             : #endif
     173           0 :         return ret;
     174             : }
     175             : 
     176           0 : static void zend_mm_mem_mmap_free(zend_mm_storage *storage, zend_mm_segment* segment)
     177             : {
     178           0 :         munmap((void*)segment, segment->size);
     179           0 : }
     180             : 
     181             : #endif
     182             : 
     183             : #ifdef HAVE_MEM_MMAP_ANON
     184             : 
     185           0 : static zend_mm_segment* zend_mm_mem_mmap_anon_alloc(zend_mm_storage *storage, size_t size)
     186             : {
     187           0 :         zend_mm_segment *ret = (zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     188           0 :         if (ret == MAP_FAILED) {
     189           0 :                 ret = NULL;
     190             :         }
     191           0 :         return ret;
     192             : }
     193             : 
     194             : # define ZEND_MM_MEM_MMAP_ANON_DSC {"mmap_anon", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_anon_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
     195             : 
     196             : #endif
     197             : 
     198             : #ifdef HAVE_MEM_MMAP_ZERO
     199             : 
     200             : static int zend_mm_dev_zero_fd = -1;
     201             : 
     202           0 : static zend_mm_storage* zend_mm_mem_mmap_zero_init(void *params)
     203             : {
     204           0 :         if (zend_mm_dev_zero_fd != -1) {
     205           0 :                 zend_mm_dev_zero_fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
     206             :         }
     207           0 :         if (zend_mm_dev_zero_fd >= 0) {
     208           0 :                 return malloc(sizeof(zend_mm_storage));
     209             :         } else {
     210           0 :                 return NULL;
     211             :         }
     212             : }
     213             : 
     214           0 : static void zend_mm_mem_mmap_zero_dtor(zend_mm_storage *storage)
     215             : {
     216           0 :         close(zend_mm_dev_zero_fd);
     217           0 :         free(storage);
     218           0 : }
     219             : 
     220           0 : static zend_mm_segment* zend_mm_mem_mmap_zero_alloc(zend_mm_storage *storage, size_t size)
     221             : {
     222           0 :         zend_mm_segment *ret = (zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zend_mm_dev_zero_fd, 0);
     223           0 :         if (ret == MAP_FAILED) {
     224           0 :                 ret = NULL;
     225             :         }
     226           0 :         return ret;
     227             : }
     228             : 
     229             : # define ZEND_MM_MEM_MMAP_ZERO_DSC {"mmap_zero", zend_mm_mem_mmap_zero_init, zend_mm_mem_mmap_zero_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_zero_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
     230             : 
     231             : #endif
     232             : 
     233             : #ifdef HAVE_MEM_WIN32
     234             : 
     235             : static zend_mm_storage* zend_mm_mem_win32_init(void *params)
     236             : {
     237             :         HANDLE heap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
     238             :         zend_mm_storage* storage;
     239             : 
     240             :         if (heap == NULL) {
     241             :                 return NULL;
     242             :         }
     243             :         storage = (zend_mm_storage*)malloc(sizeof(zend_mm_storage));
     244             :         if (storage == NULL) {
     245             :                 HeapDestroy(heap);
     246             :                 return NULL;
     247             :         }
     248             :         storage->data = (void*) heap;
     249             :         return storage;
     250             : }
     251             : 
     252             : static void zend_mm_mem_win32_dtor(zend_mm_storage *storage)
     253             : {
     254             :         HeapDestroy((HANDLE)storage->data);
     255             :         free(storage);
     256             : }
     257             : 
     258             : static void zend_mm_mem_win32_compact(zend_mm_storage *storage)
     259             : {
     260             :     HeapDestroy((HANDLE)storage->data);
     261             :     storage->data = (void*)HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
     262             : }
     263             : 
     264             : static zend_mm_segment* zend_mm_mem_win32_alloc(zend_mm_storage *storage, size_t size)
     265             : {
     266             :         return (zend_mm_segment*) HeapAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, size);
     267             : }
     268             : 
     269             : static void zend_mm_mem_win32_free(zend_mm_storage *storage, zend_mm_segment* segment)
     270             : {
     271             :         HeapFree((HANDLE)storage->data, HEAP_NO_SERIALIZE, segment);
     272             : }
     273             : 
     274             : static zend_mm_segment* zend_mm_mem_win32_realloc(zend_mm_storage *storage, zend_mm_segment* segment, size_t size)
     275             : {
     276             :         return (zend_mm_segment*) HeapReAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, segment, size);
     277             : }
     278             : 
     279             : # define ZEND_MM_MEM_WIN32_DSC {"win32", zend_mm_mem_win32_init, zend_mm_mem_win32_dtor, zend_mm_mem_win32_compact, zend_mm_mem_win32_alloc, zend_mm_mem_win32_realloc, zend_mm_mem_win32_free}
     280             : 
     281             : #endif
     282             : 
     283             : #ifdef HAVE_MEM_MALLOC
     284             : 
     285       77895 : static zend_mm_segment* zend_mm_mem_malloc_alloc(zend_mm_storage *storage, size_t size)
     286             : {
     287       77895 :         return (zend_mm_segment*)malloc(size);
     288             : }
     289             : 
     290           0 : static zend_mm_segment* zend_mm_mem_malloc_realloc(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size)
     291             : {
     292           0 :         return (zend_mm_segment*)realloc(ptr, size);
     293             : }
     294             : 
     295       77930 : static void zend_mm_mem_malloc_free(zend_mm_storage *storage, zend_mm_segment *ptr)
     296             : {
     297       77930 :         free(ptr);
     298       77930 : }
     299             : 
     300             : # define ZEND_MM_MEM_MALLOC_DSC {"malloc", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_malloc_alloc, zend_mm_mem_malloc_realloc, zend_mm_mem_malloc_free}
     301             : 
     302             : #endif
     303             : 
     304             : static const zend_mm_mem_handlers mem_handlers[] = {
     305             : #ifdef HAVE_MEM_WIN32
     306             :         ZEND_MM_MEM_WIN32_DSC,
     307             : #endif
     308             : #ifdef HAVE_MEM_MALLOC
     309             :         ZEND_MM_MEM_MALLOC_DSC,
     310             : #endif
     311             : #ifdef HAVE_MEM_MMAP_ANON
     312             :         ZEND_MM_MEM_MMAP_ANON_DSC,
     313             : #endif
     314             : #ifdef HAVE_MEM_MMAP_ZERO
     315             :         ZEND_MM_MEM_MMAP_ZERO_DSC,
     316             : #endif
     317             :         {NULL, NULL, NULL, NULL, NULL, NULL}
     318             : };
     319             : 
     320             : # define ZEND_MM_STORAGE_DTOR()                                         heap->storage->handlers->dtor(heap->storage)
     321             : # define ZEND_MM_STORAGE_ALLOC(size)                            heap->storage->handlers->_alloc(heap->storage, size)
     322             : # define ZEND_MM_STORAGE_REALLOC(ptr, size)                     heap->storage->handlers->_realloc(heap->storage, ptr, size)
     323             : # define ZEND_MM_STORAGE_FREE(ptr)                                      heap->storage->handlers->_free(heap->storage, ptr)
     324             : 
     325             : /****************/
     326             : /* Heap Manager */
     327             : /****************/
     328             : 
     329             : #define MEM_BLOCK_VALID  0x7312F8DC
     330             : #define MEM_BLOCK_FREED  0x99954317
     331             : #define MEM_BLOCK_CACHED 0xFB8277DC
     332             : #define MEM_BLOCK_GUARD  0x2A8FCC84
     333             : #define MEM_BLOCK_LEAK   0x6C5E8F2D
     334             : 
     335             : /* mm block type */
     336             : typedef struct _zend_mm_block_info {
     337             : #if ZEND_MM_COOKIES
     338             :         size_t _cookie;
     339             : #endif
     340             :         size_t _size;
     341             :         size_t _prev;
     342             : } zend_mm_block_info;
     343             : 
     344             : #if ZEND_DEBUG
     345             : 
     346             : typedef struct _zend_mm_debug_info {
     347             :         char *filename;
     348             :         uint lineno;
     349             :         char *orig_filename;
     350             :         uint orig_lineno;
     351             :         size_t size;
     352             : #if ZEND_MM_HEAP_PROTECTION
     353             :         unsigned int start_magic;
     354             : #endif
     355             : } zend_mm_debug_info;
     356             : 
     357             : #elif ZEND_MM_HEAP_PROTECTION
     358             : 
     359             : typedef struct _zend_mm_debug_info {
     360             :         size_t size;
     361             :         unsigned int start_magic;
     362             : } zend_mm_debug_info;
     363             : 
     364             : #endif
     365             : 
     366             : typedef struct _zend_mm_block {
     367             :         zend_mm_block_info info;
     368             : #if ZEND_DEBUG
     369             :         unsigned int magic;
     370             : # ifdef ZTS
     371             :         THREAD_T thread_id;
     372             : # endif
     373             :         zend_mm_debug_info debug;
     374             : #elif ZEND_MM_HEAP_PROTECTION
     375             :         zend_mm_debug_info debug;
     376             : #endif
     377             : } zend_mm_block;
     378             : 
     379             : typedef struct _zend_mm_small_free_block {
     380             :         zend_mm_block_info info;
     381             : #if ZEND_DEBUG
     382             :         unsigned int magic;
     383             : # ifdef ZTS
     384             :         THREAD_T thread_id;
     385             : # endif
     386             : #endif
     387             :         struct _zend_mm_free_block *prev_free_block;
     388             :         struct _zend_mm_free_block *next_free_block;
     389             : } zend_mm_small_free_block;
     390             : 
     391             : typedef struct _zend_mm_free_block {
     392             :         zend_mm_block_info info;
     393             : #if ZEND_DEBUG
     394             :         unsigned int magic;
     395             : # ifdef ZTS
     396             :         THREAD_T thread_id;
     397             : # endif
     398             : #endif
     399             :         struct _zend_mm_free_block *prev_free_block;
     400             :         struct _zend_mm_free_block *next_free_block;
     401             : 
     402             :         struct _zend_mm_free_block **parent;
     403             :         struct _zend_mm_free_block *child[2];
     404             : } zend_mm_free_block;
     405             : 
     406             : #define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3)
     407             : 
     408             : #define ZEND_MM_CACHE 1
     409             : #define ZEND_MM_CACHE_SIZE (ZEND_MM_NUM_BUCKETS * 4 * 1024)
     410             : 
     411             : #ifndef ZEND_MM_CACHE_STAT
     412             : # define ZEND_MM_CACHE_STAT 0
     413             : #endif
     414             : 
     415             : struct _zend_mm_heap {
     416             :         int                 use_zend_alloc;
     417             :         void               *(*_malloc)(size_t);
     418             :         void                (*_free)(void*);
     419             :         void               *(*_realloc)(void*, size_t);
     420             :         size_t              free_bitmap;
     421             :         size_t              large_free_bitmap;
     422             :         size_t              block_size;
     423             :         size_t              compact_size;
     424             :         zend_mm_segment    *segments_list;
     425             :         zend_mm_storage    *storage;
     426             :         size_t              real_size;
     427             :         size_t              real_peak;
     428             :         size_t              limit;
     429             :         size_t              size;
     430             :         size_t              peak;
     431             :         size_t              reserve_size;
     432             :         void               *reserve;
     433             :         int                 overflow;
     434             :         int                 internal;
     435             : #if ZEND_MM_CACHE
     436             :         unsigned int        cached;
     437             :         zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS];
     438             : #endif
     439             :         zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];
     440             :         zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS];
     441             :         zend_mm_free_block *rest_buckets[2];
     442             : #if ZEND_MM_CACHE_STAT
     443             :         struct {
     444             :                 int count;
     445             :                 int max_count;
     446             :                 int hit;
     447             :                 int miss;
     448             :         } cache_stat[ZEND_MM_NUM_BUCKETS+1];
     449             : #endif
     450             : };
     451             : 
     452             : #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
     453             :         (zend_mm_free_block*) ((char*)&heap->free_buckets[index * 2] + \
     454             :                 sizeof(zend_mm_free_block*) * 2 - \
     455             :                 sizeof(zend_mm_small_free_block))
     456             : 
     457             : #define ZEND_MM_REST_BUCKET(heap) \
     458             :         (zend_mm_free_block*)((char*)&heap->rest_buckets[0] + \
     459             :                 sizeof(zend_mm_free_block*) * 2 - \
     460             :                 sizeof(zend_mm_small_free_block))
     461             : 
     462             : #if ZEND_MM_COOKIES
     463             : 
     464             : static unsigned int _zend_mm_cookie = 0;
     465             : 
     466             : # define ZEND_MM_COOKIE(block) \
     467             :         (((size_t)(block)) ^ _zend_mm_cookie)
     468             : # define ZEND_MM_SET_COOKIE(block) \
     469             :         (block)->info._cookie = ZEND_MM_COOKIE(block)
     470             : # define ZEND_MM_CHECK_COOKIE(block) \
     471             :         if (UNEXPECTED((block)->info._cookie != ZEND_MM_COOKIE(block))) { \
     472             :                 zend_mm_panic("zend_mm_heap corrupted"); \
     473             :         }
     474             : #else
     475             : # define ZEND_MM_SET_COOKIE(block)
     476             : # define ZEND_MM_CHECK_COOKIE(block)
     477             : #endif
     478             : 
     479             : /* Default memory segment size */
     480             : #define ZEND_MM_SEG_SIZE   (256 * 1024)
     481             : 
     482             : /* Reserved space for error reporting in case of memory overflow */
     483             : #define ZEND_MM_RESERVE_SIZE            (8*1024)
     484             : 
     485             : #ifdef _WIN64
     486             : # define ZEND_MM_LONG_CONST(x)  (x##i64)
     487             : #else
     488             : # define ZEND_MM_LONG_CONST(x)  (x##L)
     489             : #endif
     490             : 
     491             : #define ZEND_MM_TYPE_MASK               ZEND_MM_LONG_CONST(0x3)
     492             : 
     493             : #define ZEND_MM_FREE_BLOCK              ZEND_MM_LONG_CONST(0x0)
     494             : #define ZEND_MM_USED_BLOCK              ZEND_MM_LONG_CONST(0x1)
     495             : #define ZEND_MM_GUARD_BLOCK             ZEND_MM_LONG_CONST(0x3)
     496             : 
     497             : #define ZEND_MM_BLOCK(b, type, size)    do { \
     498             :                                                                                         size_t _size = (size); \
     499             :                                                                                         (b)->info._size = (type) | _size; \
     500             :                                                                                         ZEND_MM_BLOCK_AT(b, _size)->info._prev = (type) | _size; \
     501             :                                                                                         ZEND_MM_SET_COOKIE(b); \
     502             :                                                                                 } while (0);
     503             : #define ZEND_MM_LAST_BLOCK(b)                   do { \
     504             :                 (b)->info._size = ZEND_MM_GUARD_BLOCK | ZEND_MM_ALIGNED_HEADER_SIZE; \
     505             :                 ZEND_MM_SET_MAGIC(b, MEM_BLOCK_GUARD); \
     506             :         } while (0);
     507             : #define ZEND_MM_BLOCK_SIZE(b)                   ((b)->info._size & ~ZEND_MM_TYPE_MASK)
     508             : #define ZEND_MM_IS_FREE_BLOCK(b)                (!((b)->info._size & ZEND_MM_USED_BLOCK))
     509             : #define ZEND_MM_IS_USED_BLOCK(b)                ((b)->info._size & ZEND_MM_USED_BLOCK)
     510             : #define ZEND_MM_IS_GUARD_BLOCK(b)               (((b)->info._size & ZEND_MM_TYPE_MASK) == ZEND_MM_GUARD_BLOCK)
     511             : 
     512             : #define ZEND_MM_NEXT_BLOCK(b)                   ZEND_MM_BLOCK_AT(b, ZEND_MM_BLOCK_SIZE(b))
     513             : #define ZEND_MM_PREV_BLOCK(b)                   ZEND_MM_BLOCK_AT(b, -(ssize_t)((b)->info._prev & ~ZEND_MM_TYPE_MASK))
     514             : 
     515             : #define ZEND_MM_PREV_BLOCK_IS_FREE(b)   (!((b)->info._prev & ZEND_MM_USED_BLOCK))
     516             : 
     517             : #define ZEND_MM_MARK_FIRST_BLOCK(b)             ((b)->info._prev = ZEND_MM_GUARD_BLOCK)
     518             : #define ZEND_MM_IS_FIRST_BLOCK(b)               ((b)->info._prev == ZEND_MM_GUARD_BLOCK)
     519             : 
     520             : /* optimized access */
     521             : #define ZEND_MM_FREE_BLOCK_SIZE(b)              (b)->info._size
     522             : 
     523             : /* Aligned header size */
     524             : #define ZEND_MM_ALIGNED_HEADER_SIZE                     ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_block))
     525             : #define ZEND_MM_ALIGNED_FREE_HEADER_SIZE        ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_small_free_block))
     526             : #define ZEND_MM_MIN_ALLOC_BLOCK_SIZE            ZEND_MM_ALIGNED_SIZE(ZEND_MM_ALIGNED_HEADER_SIZE + END_MAGIC_SIZE)
     527             : #define ZEND_MM_ALIGNED_MIN_HEADER_SIZE         (ZEND_MM_MIN_ALLOC_BLOCK_SIZE>ZEND_MM_ALIGNED_FREE_HEADER_SIZE?ZEND_MM_MIN_ALLOC_BLOCK_SIZE:ZEND_MM_ALIGNED_FREE_HEADER_SIZE)
     528             : #define ZEND_MM_ALIGNED_SEGMENT_SIZE            ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_segment))
     529             : 
     530             : #define ZEND_MM_MIN_SIZE                                        ((ZEND_MM_ALIGNED_MIN_HEADER_SIZE>(ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE))?(ZEND_MM_ALIGNED_MIN_HEADER_SIZE-(ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE)):0)
     531             : 
     532             : #define ZEND_MM_MAX_SMALL_SIZE                          ((ZEND_MM_NUM_BUCKETS<<ZEND_MM_ALIGNMENT_LOG2)+ZEND_MM_ALIGNED_MIN_HEADER_SIZE)
     533             : 
     534             : #define ZEND_MM_TRUE_SIZE(size)                         ((size<ZEND_MM_MIN_SIZE)?(ZEND_MM_ALIGNED_MIN_HEADER_SIZE):(ZEND_MM_ALIGNED_SIZE(size+ZEND_MM_ALIGNED_HEADER_SIZE+END_MAGIC_SIZE)))
     535             : 
     536             : #define ZEND_MM_BUCKET_INDEX(true_size)         ((true_size>>ZEND_MM_ALIGNMENT_LOG2)-(ZEND_MM_ALIGNED_MIN_HEADER_SIZE>>ZEND_MM_ALIGNMENT_LOG2))
     537             : 
     538             : #define ZEND_MM_SMALL_SIZE(true_size)           (true_size < ZEND_MM_MAX_SMALL_SIZE)
     539             : 
     540             : /* Memory calculations */
     541             : #define ZEND_MM_BLOCK_AT(blk, offset)   ((zend_mm_block *) (((char *) (blk))+(offset)))
     542             : #define ZEND_MM_DATA_OF(p)                              ((void *) (((char *) (p))+ZEND_MM_ALIGNED_HEADER_SIZE))
     543             : #define ZEND_MM_HEADER_OF(blk)                  ZEND_MM_BLOCK_AT(blk, -(int)ZEND_MM_ALIGNED_HEADER_SIZE)
     544             : 
     545             : /* Debug output */
     546             : #if ZEND_DEBUG
     547             : 
     548             : # ifdef ZTS
     549             : #  define ZEND_MM_SET_THREAD_ID(block) \
     550             :         ((zend_mm_block*)(block))->thread_id = tsrm_thread_id()
     551             : #  define ZEND_MM_BAD_THREAD_ID(block) ((block)->thread_id != tsrm_thread_id())
     552             : # else
     553             : #  define ZEND_MM_SET_THREAD_ID(block)
     554             : #  define ZEND_MM_BAD_THREAD_ID(block) 0
     555             : # endif
     556             : 
     557             : # define ZEND_MM_VALID_PTR(block) \
     558             :         zend_mm_check_ptr(heap, block, 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC)
     559             : 
     560             : # define ZEND_MM_SET_MAGIC(block, val) do { \
     561             :                 (block)->magic = (val); \
     562             :         } while (0)
     563             : 
     564             : # define ZEND_MM_CHECK_MAGIC(block, val) do { \
     565             :                 if ((block)->magic != (val)) { \
     566             :                         zend_mm_panic("zend_mm_heap corrupted"); \
     567             :                 } \
     568             :         } while (0)
     569             : 
     570             : # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) do { \
     571             :                 ((zend_mm_block*)(block))->debug.filename = __zend_filename; \
     572             :                 ((zend_mm_block*)(block))->debug.lineno = __zend_lineno; \
     573             :                 ((zend_mm_block*)(block))->debug.orig_filename = __zend_orig_filename; \
     574             :                 ((zend_mm_block*)(block))->debug.orig_lineno = __zend_orig_lineno; \
     575             :                 ZEND_MM_SET_BLOCK_SIZE(block, __size); \
     576             :                 if (set_valid) { \
     577             :                         ZEND_MM_SET_MAGIC(block, MEM_BLOCK_VALID); \
     578             :                 } \
     579             :                 if (set_thread) { \
     580             :                         ZEND_MM_SET_THREAD_ID(block); \
     581             :                 } \
     582             :         } while (0)
     583             : 
     584             : #else
     585             : 
     586             : # define ZEND_MM_VALID_PTR(ptr) EXPECTED(ptr != NULL)
     587             : 
     588             : # define ZEND_MM_SET_MAGIC(block, val)
     589             : 
     590             : # define ZEND_MM_CHECK_MAGIC(block, val)
     591             : 
     592             : # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) ZEND_MM_SET_BLOCK_SIZE(block, __size)
     593             : 
     594             : #endif
     595             : 
     596             : 
     597             : #if ZEND_MM_HEAP_PROTECTION
     598             : 
     599             : # define ZEND_MM_CHECK_PROTECTION(block) \
     600             :         do { \
     601             :                 if ((block)->debug.start_magic != _mem_block_start_magic || \
     602             :                     memcmp(ZEND_MM_END_MAGIC_PTR(block), &_mem_block_end_magic, END_MAGIC_SIZE) != 0) { \
     603             :                     zend_mm_panic("zend_mm_heap corrupted"); \
     604             :                 } \
     605             :         } while (0)
     606             : 
     607             : # define ZEND_MM_END_MAGIC_PTR(block) \
     608             :         (((char*)(ZEND_MM_DATA_OF(block))) + ((zend_mm_block*)(block))->debug.size)
     609             : 
     610             : # define END_MAGIC_SIZE sizeof(unsigned int)
     611             : 
     612             : # define ZEND_MM_SET_BLOCK_SIZE(block, __size) do { \
     613             :                 char *p; \
     614             :                 ((zend_mm_block*)(block))->debug.size = (__size); \
     615             :                 p = ZEND_MM_END_MAGIC_PTR(block); \
     616             :                 ((zend_mm_block*)(block))->debug.start_magic = _mem_block_start_magic; \
     617             :                 memcpy(p, &_mem_block_end_magic, END_MAGIC_SIZE); \
     618             :         } while (0)
     619             : 
     620             : static unsigned int _mem_block_start_magic = 0;
     621             : static unsigned int _mem_block_end_magic   = 0;
     622             : 
     623             : #else
     624             : 
     625             : # if ZEND_DEBUG
     626             : #  define ZEND_MM_SET_BLOCK_SIZE(block, _size) \
     627             :         ((zend_mm_block*)(block))->debug.size = (_size)
     628             : # else
     629             : #  define ZEND_MM_SET_BLOCK_SIZE(block, _size)
     630             : # endif
     631             : 
     632             : # define ZEND_MM_CHECK_PROTECTION(block)
     633             : 
     634             : # define END_MAGIC_SIZE 0
     635             : 
     636             : #endif
     637             : 
     638             : #if ZEND_MM_SAFE_UNLINKING
     639             : # define ZEND_MM_CHECK_BLOCK_LINKAGE(block) \
     640             :         if (UNEXPECTED((block)->info._size != ZEND_MM_BLOCK_AT(block, ZEND_MM_FREE_BLOCK_SIZE(block))->info._prev) || \
     641             :                 UNEXPECTED(!UNEXPECTED(ZEND_MM_IS_FIRST_BLOCK(block)) && \
     642             :             UNEXPECTED(ZEND_MM_PREV_BLOCK(block)->info._size != (block)->info._prev))) { \
     643             :             zend_mm_panic("zend_mm_heap corrupted"); \
     644             :         }
     645             : #define ZEND_MM_CHECK_TREE(block) \
     646             :         if (UNEXPECTED(*((block)->parent) != (block))) { \
     647             :                 zend_mm_panic("zend_mm_heap corrupted"); \
     648             :         }
     649             : #else
     650             : # define ZEND_MM_CHECK_BLOCK_LINKAGE(block)
     651             : # define ZEND_MM_CHECK_TREE(block)
     652             : #endif
     653             : 
     654             : #define ZEND_MM_LARGE_BUCKET_INDEX(S) zend_mm_high_bit(S)
     655             : 
     656             : static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_MALLOC;
     657             : static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
     658             : static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
     659             : 
     660     7921673 : static inline unsigned int zend_mm_high_bit(size_t _size)
     661             : {
     662             : #if defined(__GNUC__) && defined(i386)
     663             :         unsigned int n;
     664             : 
     665             :         __asm__("bsrl %1,%0\n\t" : "=r" (n) : "rm"  (_size));
     666             :         return n;
     667             : #elif defined(__GNUC__) && defined(__x86_64__)
     668             :         unsigned long n;
     669             : 
     670     7921673 :         __asm__("bsrq %1,%0\n\t" : "=r" (n) : "rm"  (_size));
     671     7921673 :         return (unsigned int)n;
     672             : #elif defined(_MSC_VER) && defined(_M_IX86)
     673             :         __asm {
     674             :                 bsr eax, _size
     675             :         }
     676             : #else
     677             :         unsigned int n = 0;
     678             :         while (_size != 0) {
     679             :                 _size = _size >> 1;
     680             :                 n++;
     681             :         }
     682             :         return n-1;
     683             : #endif
     684             : }
     685             : 
     686    13522634 : static inline unsigned int zend_mm_low_bit(size_t _size)
     687             : {
     688             : #if defined(__GNUC__) && defined(i386)
     689             :         unsigned int n;
     690             : 
     691             :         __asm__("bsfl %1,%0\n\t" : "=r" (n) : "rm"  (_size));
     692             :         return n;
     693             : #elif defined(__GNUC__) && defined(__x86_64__)
     694             :         unsigned long n;
     695             : 
     696    13522634 :         __asm__("bsfq %1,%0\n\t" : "=r" (n) : "rm"  (_size));
     697    13522634 :         return (unsigned int)n;
     698             : #elif defined(_MSC_VER) && defined(_M_IX86)
     699             :         __asm {
     700             :                 bsf eax, _size
     701             :    }
     702             : #else
     703             :         static const int offset[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
     704             :         unsigned int n;
     705             :         unsigned int index = 0;
     706             : 
     707             :         n = offset[_size & 15];
     708             :         while (n == 4) {
     709             :                 _size >>= 4;
     710             :                 index += n;
     711             :                 n = offset[_size & 15];
     712             :         }
     713             : 
     714             :         return index + n;
     715             : #endif
     716             : }
     717             : 
     718       35649 : static inline void zend_mm_add_to_rest_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
     719             : {
     720             :         zend_mm_free_block *prev, *next;
     721             : 
     722             :         ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
     723             : 
     724       35649 :         if (!ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block))) {
     725       35641 :                 mm_block->parent = NULL;
     726             :         }
     727             : 
     728       35649 :         prev = heap->rest_buckets[0];
     729       35649 :         next = prev->next_free_block;
     730       35649 :         mm_block->prev_free_block = prev;
     731       35649 :         mm_block->next_free_block = next;
     732       35649 :         prev->next_free_block = next->prev_free_block = mm_block;
     733       35649 : }
     734             : 
     735    19007088 : static inline void zend_mm_add_to_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
     736             : {
     737             :         size_t size;
     738             :         size_t index;
     739             : 
     740             :         ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
     741             : 
     742    19007088 :         size = ZEND_MM_FREE_BLOCK_SIZE(mm_block);
     743    19007088 :         if (EXPECTED(!ZEND_MM_SMALL_SIZE(size))) {
     744             :                 zend_mm_free_block **p;
     745             : 
     746     3296525 :                 index = ZEND_MM_LARGE_BUCKET_INDEX(size);
     747     3296525 :                 p = &heap->large_free_buckets[index];
     748     3296525 :                 mm_block->child[0] = mm_block->child[1] = NULL;
     749     3296525 :                 if (!*p) {
     750     2507899 :                         *p = mm_block;
     751     2507899 :                         mm_block->parent = p;
     752     2507899 :                         mm_block->prev_free_block = mm_block->next_free_block = mm_block;
     753     2507899 :                         heap->large_free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
     754             :                 } else {
     755             :                         size_t m;
     756             : 
     757     1216637 :                         for (m = size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
     758     1216637 :                                 zend_mm_free_block *prev = *p;
     759             : 
     760     1216637 :                                 if (ZEND_MM_FREE_BLOCK_SIZE(prev) != size) {
     761     1162027 :                                         p = &prev->child[(m >> (ZEND_MM_NUM_BUCKETS-1)) & 1];
     762     1162027 :                                         if (!*p) {
     763      734016 :                                                 *p = mm_block;
     764      734016 :                                                 mm_block->parent = p;
     765      734016 :                                                 mm_block->prev_free_block = mm_block->next_free_block = mm_block;
     766      734016 :                                                 break;
     767             :                                         }
     768             :                                 } else {
     769       54610 :                                         zend_mm_free_block *next = prev->next_free_block;
     770             : 
     771       54610 :                                         prev->next_free_block = next->prev_free_block = mm_block;
     772       54610 :                                         mm_block->next_free_block = next;
     773       54610 :                                         mm_block->prev_free_block = prev;
     774       54610 :                                         mm_block->parent = NULL;
     775       54610 :                                         break;
     776             :                                 }
     777      428011 :                         }
     778             :                 }
     779             :         } else {
     780             :                 zend_mm_free_block *prev, *next;
     781             : 
     782    15710563 :                 index = ZEND_MM_BUCKET_INDEX(size);
     783             : 
     784    15710563 :                 prev = ZEND_MM_SMALL_FREE_BUCKET(heap, index);
     785    15710563 :                 if (prev->prev_free_block == prev) {
     786     6358010 :                         heap->free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
     787             :                 }
     788    15710563 :                 next = prev->next_free_block;
     789             : 
     790    15710563 :                 mm_block->prev_free_block = prev;
     791    15710563 :                 mm_block->next_free_block = next;
     792    15710563 :                 prev->next_free_block = next->prev_free_block = mm_block;
     793             :         }
     794    19007088 : }
     795             : 
     796    18980927 : static inline void zend_mm_remove_from_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
     797             : {
     798    18980927 :         zend_mm_free_block *prev = mm_block->prev_free_block;
     799    18980927 :         zend_mm_free_block *next = mm_block->next_free_block;
     800             : 
     801             :         ZEND_MM_CHECK_MAGIC(mm_block, MEM_BLOCK_FREED);
     802             : 
     803    18980927 :         if (EXPECTED(prev == mm_block)) {
     804             :                 zend_mm_free_block **rp, **cp;
     805             : 
     806             : #if ZEND_MM_SAFE_UNLINKING
     807     3183390 :                 if (UNEXPECTED(next != mm_block)) {
     808           0 :                         zend_mm_panic("zend_mm_heap corrupted");
     809             :                 }
     810             : #endif
     811             : 
     812     3183390 :                 rp = &mm_block->child[mm_block->child[1] != NULL];
     813     3183390 :                 prev = *rp;
     814     3183390 :                 if (EXPECTED(prev == NULL)) {
     815     2891714 :                         size_t index = ZEND_MM_LARGE_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
     816             : 
     817     2891714 :                         ZEND_MM_CHECK_TREE(mm_block);
     818     2891714 :                         *mm_block->parent = NULL;
     819     2891714 :                         if (mm_block->parent == &heap->large_free_buckets[index]) {
     820     2449827 :                                 heap->large_free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
     821             :                     }
     822             :                 } else {
     823      672442 :                         while (*(cp = &(prev->child[prev->child[1] != NULL])) != NULL) {
     824       89090 :                                 prev = *cp;
     825       89090 :                                 rp = cp;
     826             :                         }
     827      291676 :                         *rp = NULL;
     828             : 
     829             : subst_block:
     830      295420 :                         ZEND_MM_CHECK_TREE(mm_block);
     831      295420 :                         *mm_block->parent = prev;
     832      295420 :                         prev->parent = mm_block->parent;
     833      295420 :                         if ((prev->child[0] = mm_block->child[0])) {
     834       88790 :                                 ZEND_MM_CHECK_TREE(prev->child[0]);
     835       88790 :                                 prev->child[0]->parent = &prev->child[0];
     836             :                         }
     837      295420 :                         if ((prev->child[1] = mm_block->child[1])) {
     838       13026 :                                 ZEND_MM_CHECK_TREE(prev->child[1]);
     839       13026 :                                 prev->child[1]->parent = &prev->child[1];
     840             :                         }
     841             :                 }
     842             :         } else {
     843             : 
     844             : #if ZEND_MM_SAFE_UNLINKING
     845    15797537 :                 if (UNEXPECTED(prev->next_free_block != mm_block) || UNEXPECTED(next->prev_free_block != mm_block)) {
     846           0 :                         zend_mm_panic("zend_mm_heap corrupted");
     847             :                 }
     848             : #endif
     849             : 
     850    15797537 :                 prev->next_free_block = next;
     851    15797537 :                 next->prev_free_block = prev;
     852             : 
     853    15797537 :                 if (EXPECTED(ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block)))) {
     854    15708509 :                         if (EXPECTED(prev == next)) {
     855     6357954 :                                 size_t index = ZEND_MM_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
     856             : 
     857     6357954 :                                 if (EXPECTED(heap->free_buckets[index*2] == heap->free_buckets[index*2+1])) {
     858     6357953 :                                         heap->free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
     859             :                                 }
     860             :                         }
     861       89028 :                 } else if (UNEXPECTED(mm_block->parent != NULL)) {
     862        3744 :                         goto subst_block;
     863             :                 }
     864             :         }
     865    18980927 : }
     866             : 
     867       58044 : static inline void zend_mm_init(zend_mm_heap *heap)
     868             : {
     869             :         zend_mm_free_block* p;
     870             :         int i;
     871             : 
     872       58044 :         heap->free_bitmap = 0;
     873       58044 :         heap->large_free_bitmap = 0;
     874             : #if ZEND_MM_CACHE
     875       58044 :         heap->cached = 0;
     876       58044 :         memset(heap->cache, 0, sizeof(heap->cache));
     877             : #endif
     878             : #if ZEND_MM_CACHE_STAT
     879             :         for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
     880             :                 heap->cache_stat[i].count = 0;
     881             :         }
     882             : #endif
     883       58044 :         p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
     884     3772860 :         for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
     885     3714816 :                 p->next_free_block = p;
     886     3714816 :                 p->prev_free_block = p;
     887     3714816 :                 p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2);
     888     3714816 :                 heap->large_free_buckets[i] = NULL;
     889             :         }
     890       58044 :         heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap);
     891       58044 : }
     892             : 
     893       19828 : static void zend_mm_del_segment(zend_mm_heap *heap, zend_mm_segment *segment)
     894             : {
     895       19828 :         zend_mm_segment **p = &heap->segments_list;
     896             : 
     897       39883 :         while (*p != segment) {
     898         227 :                 p = &(*p)->next_segment;
     899             :         }
     900       19828 :         *p = segment->next_segment;
     901       19828 :         heap->real_size -= segment->size;
     902       19828 :         ZEND_MM_STORAGE_FREE(segment);
     903       19828 : }
     904             : 
     905             : #if ZEND_MM_CACHE
     906           0 : static void zend_mm_free_cache(zend_mm_heap *heap)
     907             : {
     908             :         int i;
     909             : 
     910           0 :         for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
     911           0 :                 if (heap->cache[i]) {
     912           0 :                         zend_mm_free_block *mm_block = heap->cache[i];
     913             : 
     914           0 :                         while (mm_block) {
     915           0 :                                 size_t size = ZEND_MM_BLOCK_SIZE(mm_block);
     916           0 :                                 zend_mm_free_block *q = mm_block->prev_free_block;
     917           0 :                                 zend_mm_block *next_block = ZEND_MM_NEXT_BLOCK(mm_block);
     918             : 
     919           0 :                                 heap->cached -= size;
     920             : 
     921           0 :                                 if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) {
     922           0 :                                         mm_block = (zend_mm_free_block*)ZEND_MM_PREV_BLOCK(mm_block);
     923           0 :                                         size += ZEND_MM_FREE_BLOCK_SIZE(mm_block);
     924           0 :                                         zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block);
     925             :                                 }
     926           0 :                                 if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
     927           0 :                                         size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
     928           0 :                                         zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
     929             :                                 }
     930           0 :                                 ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size);
     931             : 
     932           0 :                                 if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
     933           0 :                                     ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_NEXT_BLOCK(mm_block))) {
     934           0 :                                         zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE));
     935             :                                 } else {
     936           0 :                                         zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block);
     937             :                                 }
     938             : 
     939           0 :                                 mm_block = q;
     940             :                         }
     941           0 :                         heap->cache[i] = NULL;
     942             : #if ZEND_MM_CACHE_STAT
     943             :                         heap->cache_stat[i].count = 0;
     944             : #endif
     945             :                 }
     946             :         }
     947           0 : }
     948             : #endif
     949             : 
     950             : #if ZEND_MM_HEAP_PROTECTION || ZEND_MM_COOKIES
     951             : static void zend_mm_random(unsigned char *buf, size_t size) /* {{{ */
     952             : {
     953             :         size_t i = 0;
     954             :         unsigned char t;
     955             : 
     956             : #ifdef ZEND_WIN32
     957             :         HCRYPTPROV   hCryptProv;
     958             :         int has_context = 0;
     959             : 
     960             :         if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) {
     961             :                 /* Could mean that the key container does not exist, let try 
     962             :                    again by asking for a new one */
     963             :                 if (GetLastError() == NTE_BAD_KEYSET) {
     964             :                         if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
     965             :                                 has_context = 1;
     966             :                         }
     967             :                 }
     968             :         } else {
     969             :                 has_context = 1;
     970             :         }
     971             :         if (has_context) {
     972             :                 do {
     973             :                         BOOL ret = CryptGenRandom(hCryptProv, size, buf);
     974             :                         CryptReleaseContext(hCryptProv, 0);
     975             :                         if (ret) {
     976             :                                 while (i < size && buf[i] != 0) {
     977             :                                         i++;
     978             :                                 }
     979             :                                 if (i == size) {
     980             :                                         return;
     981             :                                 }
     982             :                    }
     983             :                 } while (0);
     984             :         }
     985             : #elif defined(HAVE_DEV_URANDOM)
     986             :         int fd = open("/dev/urandom", 0);
     987             : 
     988             :         if (fd >= 0) {
     989             :                 if (read(fd, buf, size) == size) {
     990             :                         while (i < size && buf[i] != 0) {
     991             :                                 i++;
     992             :                         }
     993             :                         if (i == size) {
     994             :                                 close(fd);
     995             :                             return;
     996             :                         }
     997             :                 }
     998             :                 close(fd);
     999             :         }
    1000             : #endif
    1001             :         t = (unsigned char)getpid();
    1002             :         while (i < size) {
    1003             :                 do {
    1004             :                         buf[i] = ((unsigned char)rand()) ^ t;
    1005             :                 } while (buf[i] == 0);
    1006             :                 t = buf[i++] << 1;
    1007             :     }
    1008             : }
    1009             : /* }}} */
    1010             : #endif
    1011             : 
    1012             : /* Notes:
    1013             :  * - This function may alter the block_sizes values to match platform alignment
    1014             :  * - This function does *not* perform sanity checks on the arguments
    1015             :  */
    1016       19341 : ZEND_API zend_mm_heap *zend_mm_startup_ex(const zend_mm_mem_handlers *handlers, size_t block_size, size_t reserve_size, int internal, void *params)
    1017             : {
    1018             :         zend_mm_storage *storage;
    1019             :         zend_mm_heap    *heap;
    1020             : 
    1021             : #if 0
    1022             :         int i;
    1023             : 
    1024             :         printf("ZEND_MM_ALIGNMENT=%d\n", ZEND_MM_ALIGNMENT);
    1025             :         printf("ZEND_MM_ALIGNMENT_LOG2=%d\n", ZEND_MM_ALIGNMENT_LOG2);
    1026             :         printf("ZEND_MM_MIN_SIZE=%d\n", ZEND_MM_MIN_SIZE);
    1027             :         printf("ZEND_MM_MAX_SMALL_SIZE=%d\n", ZEND_MM_MAX_SMALL_SIZE);
    1028             :         printf("ZEND_MM_ALIGNED_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_HEADER_SIZE);
    1029             :         printf("ZEND_MM_ALIGNED_FREE_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_FREE_HEADER_SIZE);
    1030             :         printf("ZEND_MM_MIN_ALLOC_BLOCK_SIZE=%d\n", ZEND_MM_MIN_ALLOC_BLOCK_SIZE);
    1031             :         printf("ZEND_MM_ALIGNED_MIN_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_MIN_HEADER_SIZE);
    1032             :         printf("ZEND_MM_ALIGNED_SEGMENT_SIZE=%d\n", ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1033             :         for (i = 0; i < ZEND_MM_MAX_SMALL_SIZE; i++) {
    1034             :                 printf("%3d%c: %3ld %d %2ld\n", i, (i == ZEND_MM_MIN_SIZE?'*':' '), (long)ZEND_MM_TRUE_SIZE(i), ZEND_MM_SMALL_SIZE(ZEND_MM_TRUE_SIZE(i)), (long)ZEND_MM_BUCKET_INDEX(ZEND_MM_TRUE_SIZE(i)));
    1035             :         }
    1036             :         exit(0);
    1037             : #endif
    1038             : 
    1039             : #if ZEND_MM_HEAP_PROTECTION
    1040             :         if (_mem_block_start_magic == 0) {
    1041             :                 zend_mm_random((unsigned char*)&_mem_block_start_magic, sizeof(_mem_block_start_magic));
    1042             :         }
    1043             :         if (_mem_block_end_magic == 0) {
    1044             :                 zend_mm_random((unsigned char*)&_mem_block_end_magic, sizeof(_mem_block_end_magic));
    1045             :         }
    1046             : #endif
    1047             : #if ZEND_MM_COOKIES
    1048             :         if (_zend_mm_cookie == 0) {
    1049             :                 zend_mm_random((unsigned char*)&_zend_mm_cookie, sizeof(_zend_mm_cookie));
    1050             :         }
    1051             : #endif
    1052             : 
    1053       19341 :         if (zend_mm_low_bit(block_size) != zend_mm_high_bit(block_size)) {
    1054           0 :                 fprintf(stderr, "'block_size' must be a power of two\n");
    1055             : /* See http://support.microsoft.com/kb/190351 */
    1056             : #ifdef PHP_WIN32
    1057             :                 fflush(stderr);
    1058             : #endif
    1059           0 :                 exit(255);
    1060             :         }
    1061       19341 :         storage = handlers->init(params);
    1062       19341 :         if (!storage) {
    1063           0 :                 fprintf(stderr, "Cannot initialize zend_mm storage [%s]\n", handlers->name);
    1064             : /* See http://support.microsoft.com/kb/190351 */
    1065             : #ifdef PHP_WIN32
    1066             :                 fflush(stderr);
    1067             : #endif
    1068           0 :                 exit(255);
    1069             :         }
    1070       19341 :         storage->handlers = handlers;
    1071             : 
    1072       19341 :         heap = malloc(sizeof(struct _zend_mm_heap));
    1073       19341 :         if (heap == NULL) {
    1074           0 :                 fprintf(stderr, "Cannot allocate heap for zend_mm storage [%s]\n", handlers->name);
    1075             : #ifdef PHP_WIN32
    1076             :                 fflush(stderr);
    1077             : #endif
    1078           0 :                 exit(255);
    1079             :         }
    1080       19341 :         heap->storage = storage;
    1081       19341 :         heap->block_size = block_size;
    1082       19341 :         heap->compact_size = 0;
    1083       19341 :         heap->segments_list = NULL;
    1084       19341 :         zend_mm_init(heap);
    1085             : # if ZEND_MM_CACHE_STAT
    1086             :         memset(heap->cache_stat, 0, sizeof(heap->cache_stat));
    1087             : # endif
    1088             : 
    1089       19341 :         heap->use_zend_alloc = 1;
    1090       19341 :         heap->real_size = 0;
    1091       19341 :         heap->overflow = 0;
    1092       19341 :         heap->real_peak = 0;
    1093       19341 :         heap->limit = ZEND_MM_LONG_CONST(1)<<(ZEND_MM_NUM_BUCKETS-2);
    1094       19341 :         heap->size = 0;
    1095       19341 :         heap->peak = 0;
    1096       19341 :         heap->internal = internal;
    1097       19341 :         heap->reserve = NULL;
    1098       19341 :         heap->reserve_size = reserve_size;
    1099       19341 :         if (reserve_size > 0) {
    1100       19341 :                 heap->reserve = _zend_mm_alloc_int(heap, reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
    1101             :         }
    1102       19341 :         if (internal) {
    1103             :                 int i;
    1104             :                 zend_mm_free_block *p, *q, *orig;
    1105           0 :                 zend_mm_heap *mm_heap = _zend_mm_alloc_int(heap, sizeof(zend_mm_heap)  ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
    1106             : 
    1107           0 :                 *mm_heap = *heap;
    1108             : 
    1109           0 :                 p = ZEND_MM_SMALL_FREE_BUCKET(mm_heap, 0);
    1110           0 :                 orig = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
    1111           0 :                 for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
    1112           0 :                         q = p;
    1113           0 :                         while (q->prev_free_block != orig) {
    1114           0 :                                 q = q->prev_free_block;
    1115             :                         }
    1116           0 :                         q->prev_free_block = p;
    1117           0 :                         q = p;
    1118           0 :                         while (q->next_free_block != orig) {
    1119           0 :                                 q = q->next_free_block;
    1120             :                         }
    1121           0 :                         q->next_free_block = p;
    1122           0 :                         p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2);
    1123           0 :                         orig = (zend_mm_free_block*)((char*)orig + sizeof(zend_mm_free_block*) * 2);
    1124           0 :                         if (mm_heap->large_free_buckets[i]) {
    1125           0 :                                 mm_heap->large_free_buckets[i]->parent = &mm_heap->large_free_buckets[i];
    1126             :                         }
    1127             :                 }
    1128           0 :                 mm_heap->rest_buckets[0] = mm_heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(mm_heap);
    1129             : 
    1130           0 :                 free(heap);
    1131           0 :                 heap = mm_heap;
    1132             :         }
    1133       19341 :         return heap;
    1134             : }
    1135             : 
    1136       19341 : ZEND_API zend_mm_heap *zend_mm_startup(void)
    1137             : {
    1138             :         int i;
    1139             :         size_t seg_size;
    1140       19341 :         char *mem_type = getenv("ZEND_MM_MEM_TYPE");
    1141             :         char *tmp;
    1142             :         const zend_mm_mem_handlers *handlers;
    1143             :         zend_mm_heap *heap;
    1144             : 
    1145       19341 :         if (mem_type == NULL) {
    1146       19341 :                 i = 0;
    1147             :         } else {
    1148           0 :                 for (i = 0; mem_handlers[i].name; i++) {
    1149           0 :                         if (strcmp(mem_handlers[i].name, mem_type) == 0) {
    1150           0 :                                 break;
    1151             :                         }
    1152             :                 }
    1153           0 :                 if (!mem_handlers[i].name) {
    1154           0 :                         fprintf(stderr, "Wrong or unsupported zend_mm storage type '%s'\n", mem_type);
    1155           0 :                         fprintf(stderr, "  supported types:\n");
    1156             : /* See http://support.microsoft.com/kb/190351 */
    1157             : #ifdef PHP_WIN32
    1158             :                         fflush(stderr);
    1159             : #endif
    1160           0 :                         for (i = 0; mem_handlers[i].name; i++) {
    1161           0 :                                 fprintf(stderr, "    '%s'\n", mem_handlers[i].name);
    1162             :                         }
    1163             : /* See http://support.microsoft.com/kb/190351 */
    1164             : #ifdef PHP_WIN32
    1165             :                         fflush(stderr);
    1166             : #endif
    1167           0 :                         exit(255);
    1168             :                 }
    1169             :         }
    1170       19341 :         handlers = &mem_handlers[i];
    1171             : 
    1172       19341 :         tmp = getenv("ZEND_MM_SEG_SIZE");
    1173       19341 :         if (tmp) {
    1174           0 :                 seg_size = zend_atoi(tmp, 0);
    1175           0 :                 if (zend_mm_low_bit(seg_size) != zend_mm_high_bit(seg_size)) {
    1176           0 :                         fprintf(stderr, "ZEND_MM_SEG_SIZE must be a power of two\n");
    1177             : /* See http://support.microsoft.com/kb/190351 */
    1178             : #ifdef PHP_WIN32
    1179             :                         fflush(stderr);
    1180             : #endif
    1181           0 :                         exit(255);
    1182           0 :                 } else if (seg_size < ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE) {
    1183           0 :                         fprintf(stderr, "ZEND_MM_SEG_SIZE is too small\n");
    1184             : /* See http://support.microsoft.com/kb/190351 */
    1185             : #ifdef PHP_WIN32
    1186             :                         fflush(stderr);
    1187             : #endif
    1188           0 :                         exit(255);
    1189             :                 }
    1190             :         } else {
    1191       19341 :                 seg_size = ZEND_MM_SEG_SIZE;
    1192             :         }
    1193             : 
    1194       19341 :         heap = zend_mm_startup_ex(handlers, seg_size, ZEND_MM_RESERVE_SIZE, 0, NULL);
    1195       19341 :         if (heap) {
    1196       19341 :                 tmp = getenv("ZEND_MM_COMPACT");
    1197       19341 :                 if (tmp) {
    1198           0 :                         heap->compact_size = zend_atoi(tmp, 0);
    1199             :                 } else {
    1200       19341 :                         heap->compact_size = 2 * 1024 * 1024;
    1201             :                 }
    1202             :         }
    1203       19341 :         return heap;
    1204             : }
    1205             : 
    1206             : #if ZEND_DEBUG
    1207             : static long zend_mm_find_leaks(zend_mm_segment *segment, zend_mm_block *b)
    1208             : {
    1209             :         long leaks = 0;
    1210             :         zend_mm_block *p, *q;
    1211             : 
    1212             :         p = ZEND_MM_NEXT_BLOCK(b);
    1213             :         while (1) {
    1214             :                 if (ZEND_MM_IS_GUARD_BLOCK(p)) {
    1215             :                         ZEND_MM_CHECK_MAGIC(p, MEM_BLOCK_GUARD);
    1216             :                         segment = segment->next_segment;
    1217             :                         if (!segment) {
    1218             :                                 break;
    1219             :                         }
    1220             :                         p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1221             :                         continue;
    1222             :                 }
    1223             :                 q = ZEND_MM_NEXT_BLOCK(p);
    1224             :                 if (q <= p ||
    1225             :                     (char*)q > (char*)segment + segment->size ||
    1226             :                     p->info._size != q->info._prev) {
    1227             :                     zend_mm_panic("zend_mm_heap corrupted");
    1228             :                 }
    1229             :                 if (!ZEND_MM_IS_FREE_BLOCK(p)) {
    1230             :                         if (p->magic == MEM_BLOCK_VALID) {
    1231             :                                 if (p->debug.filename==b->debug.filename && p->debug.lineno==b->debug.lineno) {
    1232             :                                         ZEND_MM_SET_MAGIC(p, MEM_BLOCK_LEAK);
    1233             :                                         leaks++;
    1234             :                                 }
    1235             : #if ZEND_MM_CACHE
    1236             :                         } else if (p->magic == MEM_BLOCK_CACHED) {
    1237             :                                 /* skip it */
    1238             : #endif
    1239             :                         } else if (p->magic != MEM_BLOCK_LEAK) {
    1240             :                             zend_mm_panic("zend_mm_heap corrupted");
    1241             :                         }
    1242             :                 }
    1243             :                 p = q;
    1244             :         }
    1245             :         return leaks;
    1246             : }
    1247             : 
    1248             : static void zend_mm_check_leaks(zend_mm_heap *heap TSRMLS_DC)
    1249             : {
    1250             :         zend_mm_segment *segment = heap->segments_list;
    1251             :         zend_mm_block *p, *q;
    1252             :         zend_uint total = 0;
    1253             : 
    1254             :         if (!segment) {
    1255             :                 return;
    1256             :         }
    1257             :         p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1258             :         while (1) {
    1259             :                 q = ZEND_MM_NEXT_BLOCK(p);
    1260             :                 if (q <= p ||
    1261             :                     (char*)q > (char*)segment + segment->size ||
    1262             :                     p->info._size != q->info._prev) {
    1263             :                         zend_mm_panic("zend_mm_heap corrupted");
    1264             :                 }
    1265             :                 if (!ZEND_MM_IS_FREE_BLOCK(p)) {
    1266             :                         if (p->magic == MEM_BLOCK_VALID) {
    1267             :                                 long repeated;
    1268             :                                 zend_leak_info leak;
    1269             : 
    1270             :                                 ZEND_MM_SET_MAGIC(p, MEM_BLOCK_LEAK);
    1271             : 
    1272             :                                 leak.addr = ZEND_MM_DATA_OF(p);
    1273             :                                 leak.size = p->debug.size;
    1274             :                                 leak.filename = p->debug.filename;
    1275             :                                 leak.lineno = p->debug.lineno;
    1276             :                                 leak.orig_filename = p->debug.orig_filename;
    1277             :                                 leak.orig_lineno = p->debug.orig_lineno;
    1278             : 
    1279             :                                 zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC);
    1280             :                                 zend_message_dispatcher(ZMSG_MEMORY_LEAK_DETECTED, &leak TSRMLS_CC);
    1281             :                                 repeated = zend_mm_find_leaks(segment, p);
    1282             :                                 total += 1 + repeated;
    1283             :                                 if (repeated) {
    1284             :                                         zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(zend_uintptr_t)repeated TSRMLS_CC);
    1285             :                                 }
    1286             : #if ZEND_MM_CACHE
    1287             :                         } else if (p->magic == MEM_BLOCK_CACHED) {
    1288             :                                 /* skip it */
    1289             : #endif
    1290             :                         } else if (p->magic != MEM_BLOCK_LEAK) {
    1291             :                                 zend_mm_panic("zend_mm_heap corrupted");
    1292             :                         }
    1293             :                 }
    1294             :                 if (ZEND_MM_IS_GUARD_BLOCK(q)) {
    1295             :                         segment = segment->next_segment;
    1296             :                         if (!segment) {
    1297             :                                 break;
    1298             :                         }
    1299             :                         q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1300             :                 }
    1301             :                 p = q;
    1302             :         }
    1303             :         if (total) {
    1304             :                 zend_message_dispatcher(ZMSG_MEMORY_LEAKS_GRAND_TOTAL, &total TSRMLS_CC);
    1305             :         }
    1306             : }
    1307             : 
    1308             : static int zend_mm_check_ptr(zend_mm_heap *heap, void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    1309             : {
    1310             :         zend_mm_block *p;
    1311             :         int no_cache_notice = 0;
    1312             :         int had_problems = 0;
    1313             :         int valid_beginning = 1;
    1314             : 
    1315             :         if (silent==2) {
    1316             :                 silent = 1;
    1317             :                 no_cache_notice = 1;
    1318             :         } else if (silent==3) {
    1319             :                 silent = 0;
    1320             :                 no_cache_notice = 1;
    1321             :         }
    1322             :         if (!silent) {
    1323             :                 TSRMLS_FETCH();
    1324             :                 
    1325             :                 zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC);
    1326             :                 zend_debug_alloc_output("---------------------------------------\n");
    1327             :                 zend_debug_alloc_output("%s(%d) : Block "PTR_FMT" status:\n" ZEND_FILE_LINE_RELAY_CC, ptr);
    1328             :                 if (__zend_orig_filename) {
    1329             :                         zend_debug_alloc_output("%s(%d) : Actual location (location was relayed)\n" ZEND_FILE_LINE_ORIG_RELAY_CC);
    1330             :                 }
    1331             :                 if (!ptr) {
    1332             :                         zend_debug_alloc_output("NULL\n");
    1333             :                         zend_debug_alloc_output("---------------------------------------\n");
    1334             :                         return 0;
    1335             :                 }
    1336             :         }
    1337             : 
    1338             :         if (!ptr) {
    1339             :                 if (silent) {
    1340             :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1341             :                 }
    1342             :         }
    1343             : 
    1344             :         p = ZEND_MM_HEADER_OF(ptr);
    1345             : 
    1346             : #ifdef ZTS
    1347             :         if (ZEND_MM_BAD_THREAD_ID(p)) {
    1348             :                 if (!silent) {
    1349             :                         zend_debug_alloc_output("Invalid pointer: ((thread_id=0x%0.8X) != (expected=0x%0.8X))\n", (long)p->thread_id, (long)tsrm_thread_id());
    1350             :                         had_problems = 1;
    1351             :                 } else {
    1352             :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1353             :                 }
    1354             :         }
    1355             : #endif
    1356             : 
    1357             :         if (p->info._size != ZEND_MM_NEXT_BLOCK(p)->info._prev) {
    1358             :                 if (!silent) {
    1359             :                         zend_debug_alloc_output("Invalid pointer: ((size="PTR_FMT") != (next.prev="PTR_FMT"))\n", p->info._size, ZEND_MM_NEXT_BLOCK(p)->info._prev);
    1360             :                         had_problems = 1;
    1361             :                 } else {
    1362             :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1363             :                 }
    1364             :         }
    1365             :         if (p->info._prev != ZEND_MM_GUARD_BLOCK &&
    1366             :             ZEND_MM_PREV_BLOCK(p)->info._size != p->info._prev) {
    1367             :                 if (!silent) {
    1368             :                         zend_debug_alloc_output("Invalid pointer: ((prev="PTR_FMT") != (prev.size="PTR_FMT"))\n", p->info._prev, ZEND_MM_PREV_BLOCK(p)->info._size);
    1369             :                         had_problems = 1;
    1370             :                 } else {
    1371             :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1372             :                 }
    1373             :         }
    1374             : 
    1375             :         if (had_problems) {
    1376             :                 zend_debug_alloc_output("---------------------------------------\n");
    1377             :                 return 0;
    1378             :         }
    1379             : 
    1380             :         if (!silent) {
    1381             :                 zend_debug_alloc_output("%10s\t","Beginning:  ");
    1382             :         }
    1383             : 
    1384             :         if (!ZEND_MM_IS_USED_BLOCK(p)) {
    1385             :                 if (!silent) {
    1386             :                         if (p->magic != MEM_BLOCK_FREED) {
    1387             :                                 zend_debug_alloc_output("Freed (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
    1388             :                         } else {
    1389             :                                 zend_debug_alloc_output("Freed\n");
    1390             :                         }
    1391             :                         had_problems = 1;
    1392             :                 } else {
    1393             :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1394             :                 }
    1395             :         } else if (ZEND_MM_IS_GUARD_BLOCK(p)) {
    1396             :                 if (!silent) {
    1397             :                         if (p->magic != MEM_BLOCK_FREED) {
    1398             :                                 zend_debug_alloc_output("Guard (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
    1399             :                         } else {
    1400             :                                 zend_debug_alloc_output("Guard\n");
    1401             :                         }
    1402             :                         had_problems = 1;
    1403             :                 } else {
    1404             :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1405             :                 }
    1406             :         } else {
    1407             :                 switch (p->magic) {
    1408             :                         case MEM_BLOCK_VALID:
    1409             :                         case MEM_BLOCK_LEAK:
    1410             :                                 if (!silent) {
    1411             :                                         zend_debug_alloc_output("OK (allocated on %s:%d, %d bytes)\n", p->debug.filename, p->debug.lineno, (int)p->debug.size);
    1412             :                                 }
    1413             :                                 break; /* ok */
    1414             :                         case MEM_BLOCK_CACHED:
    1415             :                                 if (!no_cache_notice) {
    1416             :                                         if (!silent) {
    1417             :                                                 zend_debug_alloc_output("Cached\n");
    1418             :                                                 had_problems = 1;
    1419             :                                         } else {
    1420             :                                                 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1421             :                                         }
    1422             :                                 }
    1423             :                         case MEM_BLOCK_FREED:
    1424             :                                 if (!silent) {
    1425             :                                         zend_debug_alloc_output("Freed (invalid)\n");
    1426             :                                         had_problems = 1;
    1427             :                                 } else {
    1428             :                                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1429             :                                 }
    1430             :                                 break;
    1431             :                         case MEM_BLOCK_GUARD:
    1432             :                                 if (!silent) {
    1433             :                                         zend_debug_alloc_output("Guard (invalid)\n");
    1434             :                                         had_problems = 1;
    1435             :                                 } else {
    1436             :                                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1437             :                                 }
    1438             :                                 break;
    1439             :                         default:
    1440             :                                 if (!silent) {
    1441             :                                         zend_debug_alloc_output("Unknown (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_VALID);
    1442             :                                         had_problems = 1;
    1443             :                                         valid_beginning = 0;
    1444             :                                 } else {
    1445             :                                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1446             :                                 }
    1447             :                                 break;
    1448             :                 }
    1449             :         }
    1450             : 
    1451             : #if ZEND_MM_HEAP_PROTECTION
    1452             :         if (!valid_beginning) {
    1453             :                 if (!silent) {
    1454             :                         zend_debug_alloc_output("%10s\t", "Start:");
    1455             :                         zend_debug_alloc_output("Unknown\n");
    1456             :                         zend_debug_alloc_output("%10s\t", "End:");
    1457             :                         zend_debug_alloc_output("Unknown\n");
    1458             :                 }
    1459             :         } else {
    1460             :                 char *end_magic = ZEND_MM_END_MAGIC_PTR(p);
    1461             : 
    1462             :                 if (p->debug.start_magic == _mem_block_start_magic) {
    1463             :                         if (!silent) {
    1464             :                                 zend_debug_alloc_output("%10s\t", "Start:");
    1465             :                                 zend_debug_alloc_output("OK\n");
    1466             :                         }
    1467             :                 } else {
    1468             :                         char *overflow_ptr, *magic_ptr=(char *) &_mem_block_start_magic;
    1469             :                         int overflows=0;
    1470             :                         int i;
    1471             : 
    1472             :                         if (silent) {
    1473             :                                 return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1474             :                         }
    1475             :                         had_problems = 1;
    1476             :                         overflow_ptr = (char *) &p->debug.start_magic;
    1477             :                         i = END_MAGIC_SIZE;
    1478             :                         while (--i >= 0) {
    1479             :                                 if (overflow_ptr[i]!=magic_ptr[i]) {
    1480             :                                         overflows++;
    1481             :                                 }
    1482             :                         }
    1483             :                         zend_debug_alloc_output("%10s\t", "Start:");
    1484             :                         zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", p->debug.start_magic, _mem_block_start_magic);
    1485             :                         zend_debug_alloc_output("%10s\t","");
    1486             :                         if (overflows >= END_MAGIC_SIZE) {
    1487             :                                 zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
    1488             :                         } else {
    1489             :                                 zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
    1490             :                         }
    1491             :                 }
    1492             :                 if (memcmp(end_magic, &_mem_block_end_magic, END_MAGIC_SIZE)==0) {
    1493             :                         if (!silent) {
    1494             :                                 zend_debug_alloc_output("%10s\t", "End:");
    1495             :                                 zend_debug_alloc_output("OK\n");
    1496             :                         }
    1497             :                 } else {
    1498             :                         char *overflow_ptr, *magic_ptr=(char *) &_mem_block_end_magic;
    1499             :                         int overflows=0;
    1500             :                         int i;
    1501             : 
    1502             :                         if (silent) {
    1503             :                                 return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1504             :                         }
    1505             :                         had_problems = 1;
    1506             :                         overflow_ptr = (char *) end_magic;
    1507             : 
    1508             :                         for (i=0; i < END_MAGIC_SIZE; i++) {
    1509             :                                 if (overflow_ptr[i]!=magic_ptr[i]) {
    1510             :                                         overflows++;
    1511             :                                 }
    1512             :                         }
    1513             : 
    1514             :                         zend_debug_alloc_output("%10s\t", "End:");
    1515             :                         zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", *end_magic, _mem_block_end_magic);
    1516             :                         zend_debug_alloc_output("%10s\t","");
    1517             :                         if (overflows >= END_MAGIC_SIZE) {
    1518             :                                 zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
    1519             :                         } else {
    1520             :                                 zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
    1521             :                         }
    1522             :                 }
    1523             :         }
    1524             : #endif
    1525             : 
    1526             :         if (!silent) {
    1527             :                 zend_debug_alloc_output("---------------------------------------\n");
    1528             :         }
    1529             :         return ((!had_problems) ? 1 : 0);
    1530             : }
    1531             : 
    1532             : static int zend_mm_check_heap(zend_mm_heap *heap, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    1533             : {
    1534             :         zend_mm_segment *segment = heap->segments_list;
    1535             :         zend_mm_block *p, *q;
    1536             :         int errors = 0;
    1537             : 
    1538             :         if (!segment) {
    1539             :                 return 0;
    1540             :         }
    1541             :         p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1542             :         while (1) {
    1543             :                 q = ZEND_MM_NEXT_BLOCK(p);
    1544             :                 if (q <= p ||
    1545             :                     (char*)q > (char*)segment + segment->size ||
    1546             :                     p->info._size != q->info._prev) {
    1547             :                         zend_mm_panic("zend_mm_heap corrupted");
    1548             :                 }
    1549             :                 if (!ZEND_MM_IS_FREE_BLOCK(p)) {
    1550             :                         if (p->magic == MEM_BLOCK_VALID || p->magic == MEM_BLOCK_LEAK) {
    1551             :                                 if (!zend_mm_check_ptr(heap, ZEND_MM_DATA_OF(p), (silent?2:3) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC)) {
    1552             :                                         errors++;
    1553             :                                 }
    1554             : #if ZEND_MM_CACHE
    1555             :                         } else if (p->magic == MEM_BLOCK_CACHED) {
    1556             :                                 /* skip it */
    1557             : #endif
    1558             :                         } else if (p->magic != MEM_BLOCK_LEAK) {
    1559             :                                 zend_mm_panic("zend_mm_heap corrupted");
    1560             :                         }
    1561             :                 }
    1562             :                 if (ZEND_MM_IS_GUARD_BLOCK(q)) {
    1563             :                         segment = segment->next_segment;
    1564             :                         if (!segment) {
    1565             :                                 return errors;
    1566             :                         }
    1567             :                         q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1568             :                 }
    1569             :                 p = q;
    1570             :         }
    1571             : }
    1572             : #endif
    1573             : 
    1574       58079 : ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, int full_shutdown, int silent TSRMLS_DC)
    1575             : {
    1576             :         zend_mm_storage *storage;
    1577             :         zend_mm_segment *segment;
    1578             :         zend_mm_segment *prev;
    1579             :         int internal;
    1580             : 
    1581       58079 :         if (heap->reserve) {
    1582             : #if ZEND_DEBUG
    1583             :                 if (!silent) {
    1584             :                         _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
    1585             :                 }
    1586             : #endif
    1587       58079 :                 heap->reserve = NULL;
    1588             :         }
    1589             : 
    1590             : #if ZEND_MM_CACHE_STAT
    1591             :         if (full_shutdown) {
    1592             :                 FILE *f;
    1593             : 
    1594             :                 f = fopen("zend_mm.log", "w");
    1595             :                 if (f) {
    1596             :                         int i,j;
    1597             :                         size_t size, true_size, min_size, max_size;
    1598             :                         int hit = 0, miss = 0;
    1599             : 
    1600             :                         fprintf(f, "\nidx min_size max_size true_size  max_len     hits   misses\n");
    1601             :                         size = 0;
    1602             :                         while (1) {
    1603             :                                 true_size = ZEND_MM_TRUE_SIZE(size);
    1604             :                                 if (ZEND_MM_SMALL_SIZE(true_size)) {
    1605             :                                         min_size = size;
    1606             :                                         i = ZEND_MM_BUCKET_INDEX(true_size);
    1607             :                                         size++;
    1608             :                                         while (1) {
    1609             :                                                 true_size = ZEND_MM_TRUE_SIZE(size);
    1610             :                                                 if (ZEND_MM_SMALL_SIZE(true_size)) {
    1611             :                                                         j = ZEND_MM_BUCKET_INDEX(true_size);
    1612             :                                                         if (j > i) {
    1613             :                                                                 max_size = size-1;
    1614             :                                                                 break;
    1615             :                                                         }
    1616             :                                                 } else {
    1617             :                                                         max_size = size-1;
    1618             :                                                         break;
    1619             :                                                 }
    1620             :                                                 size++;
    1621             :                                         }
    1622             :                                         hit += heap->cache_stat[i].hit;
    1623             :                                         miss += heap->cache_stat[i].miss;
    1624             :                                         fprintf(f, "%2d %8d %8d %9d %8d %8d %8d\n", i, (int)min_size, (int)max_size, ZEND_MM_TRUE_SIZE(max_size), heap->cache_stat[i].max_count, heap->cache_stat[i].hit, heap->cache_stat[i].miss);
    1625             :                                 } else {
    1626             :                                         break;
    1627             :                                 }
    1628             :                         }
    1629             :                         fprintf(f, "                                        %8d %8d\n", hit, miss);
    1630             :                         fprintf(f, "                                        %8d %8d\n", heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit, heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss);
    1631             :                         fclose(f);
    1632             :                 }
    1633             :         }
    1634             : #endif
    1635             : 
    1636             : #if ZEND_DEBUG
    1637             :         if (!silent) {
    1638             :                 zend_mm_check_leaks(heap TSRMLS_CC);
    1639             :         }
    1640             : #endif
    1641             : 
    1642       58079 :         internal = heap->internal;
    1643       58079 :         storage = heap->storage;
    1644       58079 :         segment = heap->segments_list;
    1645      174260 :         while (segment) {
    1646       58102 :                 prev = segment;
    1647       58102 :                 segment = segment->next_segment;
    1648       58102 :                 ZEND_MM_STORAGE_FREE(prev);
    1649             :         }
    1650       58079 :         if (full_shutdown) {
    1651       19376 :                 storage->handlers->dtor(storage);
    1652       19376 :                 if (!internal) {
    1653       19376 :                         free(heap);
    1654             :                 }
    1655             :         } else {
    1656       77406 :                 if (heap->compact_size &&
    1657       38703 :                     heap->real_peak > heap->compact_size) {
    1658           1 :                         storage->handlers->compact(storage);
    1659             :                 }
    1660       38703 :                 heap->segments_list = NULL;
    1661       38703 :                 zend_mm_init(heap);
    1662       38703 :                 heap->real_size = 0;
    1663       38703 :                 heap->real_peak = 0;
    1664       38703 :                 heap->size = 0;
    1665       38703 :                 heap->peak = 0;
    1666       38703 :                 if (heap->reserve_size) {
    1667       38703 :                         heap->reserve = _zend_mm_alloc_int(heap, heap->reserve_size  ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
    1668             :                 }
    1669       38703 :                 heap->overflow = 0;
    1670             :         }
    1671       58079 : }
    1672             : 
    1673           0 : static void zend_mm_safe_error(zend_mm_heap *heap,
    1674             :         const char *format,
    1675             :         size_t limit,
    1676             : #if ZEND_DEBUG
    1677             :         const char *filename,
    1678             :         uint lineno,
    1679             : #endif
    1680             :         size_t size)
    1681             : {
    1682           0 :         if (heap->reserve) {
    1683           0 :                 _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
    1684           0 :                 heap->reserve = NULL;
    1685             :         }
    1686           0 :         if (heap->overflow == 0) {
    1687             :                 char *error_filename;
    1688             :                 uint error_lineno;
    1689             :                 TSRMLS_FETCH();
    1690           0 :                 if (zend_is_compiling(TSRMLS_C)) {
    1691           0 :                         error_filename = zend_get_compiled_filename(TSRMLS_C);
    1692           0 :                         error_lineno = zend_get_compiled_lineno(TSRMLS_C);
    1693           0 :                 } else if (EG(in_execution)) {
    1694           0 :                         error_filename = EG(active_op_array)?EG(active_op_array)->filename:NULL;
    1695           0 :                         error_lineno = EG(opline_ptr)?(*EG(opline_ptr))->lineno:0;
    1696             :                 } else {
    1697           0 :                         error_filename = NULL;
    1698           0 :                         error_lineno = 0;
    1699             :                 }
    1700           0 :                 if (!error_filename) {
    1701           0 :                         error_filename = "Unknown";
    1702             :                 }
    1703           0 :                 heap->overflow = 1;
    1704           0 :                 zend_try {
    1705           0 :                         zend_error_noreturn(E_ERROR,
    1706             :                                 format,
    1707             :                                 limit,
    1708             : #if ZEND_DEBUG
    1709             :                                 filename,
    1710             :                                 lineno,
    1711             : #endif
    1712             :                                 size);
    1713           0 :                 } zend_catch {
    1714           0 :                         if (heap->overflow == 2) {
    1715           0 :                                 fprintf(stderr, "\nFatal error: ");
    1716           0 :                                 fprintf(stderr,
    1717             :                                         format,
    1718             :                                         limit,
    1719             : #if ZEND_DEBUG
    1720             :                                         filename,
    1721             :                                         lineno,
    1722             : #endif
    1723             :                                         size);
    1724           0 :                                 fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno);
    1725             :                         }
    1726             : /* See http://support.microsoft.com/kb/190351 */
    1727             : #ifdef PHP_WIN32
    1728             :                         fflush(stderr);
    1729             : #endif
    1730           0 :                 } zend_end_try();
    1731             :         } else {
    1732           0 :                 heap->overflow = 2;
    1733             :         }
    1734           0 :         zend_bailout();
    1735           0 : }
    1736             : 
    1737     1714093 : static zend_mm_free_block *zend_mm_search_large_block(zend_mm_heap *heap, size_t true_size)
    1738             : {
    1739             :         zend_mm_free_block *best_fit;
    1740     1714093 :         size_t index = ZEND_MM_LARGE_BUCKET_INDEX(true_size);
    1741     1714093 :         size_t bitmap = heap->large_free_bitmap >> index;
    1742             :         zend_mm_free_block *p;
    1743             : 
    1744     1714093 :         if (bitmap == 0) {
    1745       77326 :                 return NULL;
    1746             :         }
    1747             : 
    1748     1636767 :         if (UNEXPECTED((bitmap & 1) != 0)) {
    1749             :                 /* Search for best "large" free block */
    1750      648022 :                 zend_mm_free_block *rst = NULL;
    1751             :                 size_t m;
    1752      648022 :                 size_t best_size = -1;
    1753             : 
    1754      648022 :                 best_fit = NULL;
    1755      648022 :                 p = heap->large_free_buckets[index];
    1756      807357 :                 for (m = true_size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
    1757      807357 :                         if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
    1758      381415 :                                 return p->next_free_block;
    1759      643013 :                         } else if (ZEND_MM_FREE_BLOCK_SIZE(p) >= true_size &&
    1760      217071 :                                    ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
    1761      204709 :                                 best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
    1762      204709 :                                 best_fit = p;
    1763             :                         }
    1764      425942 :                         if ((m & (ZEND_MM_LONG_CONST(1) << (ZEND_MM_NUM_BUCKETS-1))) == 0) {
    1765      247039 :                                 if (p->child[1]) {
    1766       50113 :                                         rst = p->child[1];
    1767             :                                 }
    1768      247039 :                                 if (p->child[0]) {
    1769       96810 :                                         p = p->child[0];
    1770             :                                 } else {
    1771      150229 :                                         break;
    1772             :                                 }
    1773      178903 :                         } else if (p->child[1]) {
    1774       62525 :                                 p = p->child[1];
    1775             :                         } else {
    1776      116378 :                                 break;
    1777             :                         }
    1778      159335 :                 }
    1779             : 
    1780      303820 :                 for (p = rst; p; p = p->child[p->child[0] != NULL]) {
    1781       37213 :                         if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
    1782           0 :                                 return p->next_free_block;
    1783       74426 :                         } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
    1784       37213 :                                    ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
    1785       11251 :                                 best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
    1786       11251 :                                 best_fit = p;
    1787             :                         }
    1788             :                 }
    1789             : 
    1790      266607 :                 if (best_fit) {
    1791      152478 :                         return best_fit->next_free_block;
    1792             :                 }
    1793      114129 :                 bitmap = bitmap >> 1;
    1794      114129 :                 if (!bitmap) {
    1795         569 :                         return NULL;
    1796             :                 }
    1797      113560 :                 index++;
    1798             :         }
    1799             : 
    1800             :         /* Search for smallest "large" free block */
    1801     1102305 :         best_fit = p = heap->large_free_buckets[index + zend_mm_low_bit(bitmap)];
    1802     2226499 :         while ((p = p->child[p->child[0] != NULL])) {
    1803       21889 :                 if (ZEND_MM_FREE_BLOCK_SIZE(p) < ZEND_MM_FREE_BLOCK_SIZE(best_fit)) {
    1804        5225 :                         best_fit = p;
    1805             :                 }
    1806             :         }
    1807     1102305 :         return best_fit->next_free_block;
    1808             : }
    1809             : 
    1810    60906336 : static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    1811             : {
    1812             :         zend_mm_free_block *best_fit;
    1813    60906336 :         size_t true_size = ZEND_MM_TRUE_SIZE(size);
    1814             :         size_t block_size;
    1815             :         size_t remaining_size;
    1816             :         size_t segment_size;
    1817             :         zend_mm_segment *segment;
    1818    60906336 :         int keep_rest = 0;
    1819             : 
    1820    60906336 :         if (EXPECTED(ZEND_MM_SMALL_SIZE(true_size))) {
    1821    59799780 :                 size_t index = ZEND_MM_BUCKET_INDEX(true_size);
    1822             :                 size_t bitmap;
    1823             : 
    1824    59799780 :                 if (UNEXPECTED(true_size < size)) {
    1825           0 :                         goto out_of_memory;
    1826             :                 }
    1827             : #if ZEND_MM_CACHE
    1828    59799780 :                 if (EXPECTED(heap->cache[index] != NULL)) {
    1829             :                         /* Get block from cache */
    1830             : #if ZEND_MM_CACHE_STAT
    1831             :                         heap->cache_stat[index].count--;
    1832             :                         heap->cache_stat[index].hit++;
    1833             : #endif
    1834    46791255 :                         best_fit = heap->cache[index];
    1835    46791255 :                         heap->cache[index] = best_fit->prev_free_block;
    1836    46791255 :                         heap->cached -= true_size;
    1837             :                         ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
    1838             :                         ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
    1839    46791255 :                         return ZEND_MM_DATA_OF(best_fit);
    1840             :                 }
    1841             : #if ZEND_MM_CACHE_STAT
    1842             :                 heap->cache_stat[index].miss++;
    1843             : #endif
    1844             : #endif
    1845             : 
    1846    13008525 :                 bitmap = heap->free_bitmap >> index;
    1847    13008525 :                 if (bitmap) {
    1848             :                         /* Found some "small" free block that can be used */
    1849    12400988 :                         index += zend_mm_low_bit(bitmap);
    1850    12400988 :                         best_fit = heap->free_buckets[index*2];
    1851             : #if ZEND_MM_CACHE_STAT
    1852             :                         heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit++;
    1853             : #endif
    1854    12400988 :                         goto zend_mm_finished_searching_for_block;
    1855             :                 }
    1856             :         }
    1857             : 
    1858             : #if ZEND_MM_CACHE_STAT
    1859             :         heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss++;
    1860             : #endif
    1861             : 
    1862     1714093 :         best_fit = zend_mm_search_large_block(heap, true_size);
    1863             : 
    1864     1714093 :         if (!best_fit && heap->real_size >= heap->limit - heap->block_size) {
    1865           0 :                 zend_mm_free_block *p = heap->rest_buckets[0];
    1866           0 :                 size_t best_size = -1;
    1867             : 
    1868           0 :                 while (p != ZEND_MM_REST_BUCKET(heap)) {
    1869           0 :                         if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
    1870           0 :                                 best_fit = p;
    1871           0 :                                 goto zend_mm_finished_searching_for_block;
    1872           0 :                         } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
    1873           0 :                                    ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
    1874           0 :                                 best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
    1875           0 :                                 best_fit = p;
    1876             :                         }
    1877           0 :                         p = p->prev_free_block;
    1878             :                 }
    1879             :         }
    1880             : 
    1881     1714093 :         if (!best_fit) {
    1882       77895 :                 if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
    1883             :                         /* Make sure we add a memory block which is big enough,
    1884             :                            segment must have header "size" and trailer "guard" block */
    1885          14 :                         segment_size = true_size + ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE;
    1886          14 :                         segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
    1887          14 :                         keep_rest = 1;
    1888             :                 } else {
    1889       77881 :                         segment_size = heap->block_size;
    1890             :                 }
    1891             : 
    1892       77895 :                 HANDLE_BLOCK_INTERRUPTIONS();
    1893             : 
    1894      155790 :                 if (segment_size < true_size ||
    1895       77895 :                     heap->real_size + segment_size > heap->limit) {
    1896             :                         /* Memory limit overflow */
    1897             : #if ZEND_MM_CACHE
    1898           0 :                         zend_mm_free_cache(heap);
    1899             : #endif
    1900           0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    1901             : #if ZEND_DEBUG
    1902             :                         zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted at %s:%d (tried to allocate %lu bytes)", heap->limit, __zend_filename, __zend_lineno, size);
    1903             : #else
    1904           0 :                         zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %lu bytes)", heap->limit, size);
    1905             : #endif
    1906             :                 }
    1907             : 
    1908       77895 :                 segment = (zend_mm_segment *) ZEND_MM_STORAGE_ALLOC(segment_size);
    1909             : 
    1910       77895 :                 if (!segment) {
    1911             :                         /* Storage manager cannot allocate memory */
    1912             : #if ZEND_MM_CACHE
    1913           0 :                         zend_mm_free_cache(heap);
    1914             : #endif
    1915           0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    1916             : out_of_memory:
    1917             : #if ZEND_DEBUG
    1918             :                         zend_mm_safe_error(heap, "Out of memory (allocated %ld) at %s:%d (tried to allocate %lu bytes)", heap->real_size, __zend_filename, __zend_lineno, size);
    1919             : #else
    1920           0 :                         zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %lu bytes)", heap->real_size, size);
    1921             : #endif
    1922           0 :                         return NULL;
    1923             :                 }
    1924             : 
    1925       77895 :                 heap->real_size += segment_size;
    1926       77895 :                 if (heap->real_size > heap->real_peak) {
    1927       58079 :                         heap->real_peak = heap->real_size;
    1928             :                 }
    1929             : 
    1930       77895 :                 segment->size = segment_size;
    1931       77895 :                 segment->next_segment = heap->segments_list;
    1932       77895 :                 heap->segments_list = segment;
    1933             : 
    1934       77895 :                 best_fit = (zend_mm_free_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1935       77895 :                 ZEND_MM_MARK_FIRST_BLOCK(best_fit);
    1936             : 
    1937       77895 :                 block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
    1938             : 
    1939       77895 :                 ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(best_fit, block_size));
    1940             : 
    1941             :         } else {
    1942             : zend_mm_finished_searching_for_block:
    1943             :                 /* remove from free list */
    1944    14037186 :                 HANDLE_BLOCK_INTERRUPTIONS();
    1945             :                 ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_FREED);
    1946             :                 ZEND_MM_CHECK_COOKIE(best_fit);
    1947    14037186 :                 ZEND_MM_CHECK_BLOCK_LINKAGE(best_fit);
    1948    14037186 :                 zend_mm_remove_from_free_list(heap, best_fit);
    1949             : 
    1950    14037186 :                 block_size = ZEND_MM_FREE_BLOCK_SIZE(best_fit);
    1951             :         }
    1952             : 
    1953    14115081 :         remaining_size = block_size - true_size;
    1954             : 
    1955    14115081 :         if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
    1956    10126331 :                 true_size = block_size;
    1957    10126331 :                 ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
    1958             :         } else {
    1959             :                 zend_mm_free_block *new_free_block;
    1960             : 
    1961             :                 /* prepare new free block */
    1962     3988750 :                 ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
    1963     3988750 :                 new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(best_fit, true_size);
    1964     3988750 :                 ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
    1965             : 
    1966             :                 /* add the new free block to the free list */
    1967     3988750 :                 if (EXPECTED(!keep_rest)) {
    1968     3988736 :                         zend_mm_add_to_free_list(heap, new_free_block);
    1969             :                 } else {
    1970          14 :                         zend_mm_add_to_rest_list(heap, new_free_block);
    1971             :                 }
    1972             :         }
    1973             : 
    1974             :         ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 1);
    1975             : 
    1976    14115081 :         heap->size += true_size;
    1977    14115081 :         if (heap->peak < heap->size) {
    1978      119370 :                 heap->peak = heap->size;
    1979             :         }
    1980             : 
    1981    14115081 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1982             : 
    1983    14115081 :         return ZEND_MM_DATA_OF(best_fit);
    1984             : }
    1985             : 
    1986             : 
    1987    60847827 : static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    1988             : {
    1989             :         zend_mm_block *mm_block;
    1990             :         zend_mm_block *next_block;
    1991             :         size_t size;
    1992             : 
    1993    60847827 :         if (!ZEND_MM_VALID_PTR(p)) {
    1994           0 :                 return;
    1995             :         }
    1996             : 
    1997    60847827 :         mm_block = ZEND_MM_HEADER_OF(p);
    1998    60847827 :         size = ZEND_MM_BLOCK_SIZE(mm_block);
    1999             :         ZEND_MM_CHECK_PROTECTION(mm_block);
    2000             : 
    2001             : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
    2002             :         memset(ZEND_MM_DATA_OF(mm_block), 0x5a, mm_block->debug.size);
    2003             : #endif
    2004             : 
    2005             : #if ZEND_MM_CACHE
    2006    60847827 :         if (EXPECTED(ZEND_MM_SMALL_SIZE(size)) && EXPECTED(heap->cached < ZEND_MM_CACHE_SIZE)) {
    2007    46798345 :                 size_t index = ZEND_MM_BUCKET_INDEX(size);
    2008    46798345 :                 zend_mm_free_block **cache = &heap->cache[index];
    2009             : 
    2010    46798345 :                 ((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
    2011    46798345 :                 *cache = (zend_mm_free_block*)mm_block;
    2012    46798345 :                 heap->cached += size;
    2013             :                 ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
    2014             : #if ZEND_MM_CACHE_STAT
    2015             :                 if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
    2016             :                         heap->cache_stat[index].max_count = heap->cache_stat[index].count;
    2017             :                 }
    2018             : #endif
    2019    46798345 :                 return;
    2020             :         }
    2021             : #endif
    2022             : 
    2023    14049482 :         HANDLE_BLOCK_INTERRUPTIONS();
    2024             : 
    2025    14049482 :         heap->size -= size;
    2026             : 
    2027    14049482 :         next_block = ZEND_MM_BLOCK_AT(mm_block, size);
    2028    14049482 :         if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
    2029     2662898 :                 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
    2030     2662898 :                 size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
    2031             :         }
    2032    14049482 :         if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) {
    2033     1241703 :                 mm_block = ZEND_MM_PREV_BLOCK(mm_block);
    2034     1241703 :                 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block);
    2035     1241703 :                 size += ZEND_MM_FREE_BLOCK_SIZE(mm_block);
    2036             :         }
    2037    14123621 :         if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
    2038       54311 :             ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(mm_block, size))) {
    2039       19828 :                 zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE));
    2040             :         } else {
    2041    14029654 :                 ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size);
    2042    14029654 :                 zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block);
    2043             :         }
    2044    14049482 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    2045             : }
    2046             : 
    2047    11148671 : static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2048             : {
    2049    11148671 :         zend_mm_block *mm_block = ZEND_MM_HEADER_OF(p);
    2050             :         zend_mm_block *next_block;
    2051             :         size_t true_size;
    2052             :         size_t orig_size;
    2053             :         void *ptr;
    2054             : 
    2055    11148671 :         if (UNEXPECTED(!p) || !ZEND_MM_VALID_PTR(p)) {
    2056     6100244 :                 return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2057             :         }
    2058     5048427 :         mm_block = ZEND_MM_HEADER_OF(p);
    2059     5048427 :         true_size = ZEND_MM_TRUE_SIZE(size);
    2060     5048427 :         orig_size = ZEND_MM_BLOCK_SIZE(mm_block);
    2061             :         ZEND_MM_CHECK_PROTECTION(mm_block);
    2062             : 
    2063     5048427 :         if (UNEXPECTED(true_size < size)) {
    2064           0 :                 goto out_of_memory;
    2065             :         }
    2066             : 
    2067     5048427 :         if (true_size <= orig_size) {
    2068     2082080 :                 size_t remaining_size = orig_size - true_size;
    2069             : 
    2070     2082080 :                 if (remaining_size >= ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
    2071             :                         zend_mm_free_block *new_free_block;
    2072             : 
    2073       23442 :                         HANDLE_BLOCK_INTERRUPTIONS();
    2074       23442 :                         next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
    2075       23442 :                         if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
    2076        7181 :                                 remaining_size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
    2077        7181 :                                 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
    2078             :                         }
    2079             : 
    2080             :                         /* prepare new free block */
    2081       23442 :                         ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2082       23442 :                         new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
    2083             : 
    2084       23442 :                         ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
    2085             : 
    2086             :                         /* add the new free block to the free list */
    2087       23442 :                         zend_mm_add_to_free_list(heap, new_free_block);
    2088       23442 :                         heap->size += (true_size - orig_size);
    2089       23442 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    2090             :                 }
    2091             :                 ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
    2092     2082080 :                 return p;
    2093             :         }
    2094             : 
    2095             : #if ZEND_MM_CACHE
    2096     2966347 :         if (ZEND_MM_SMALL_SIZE(true_size)) {
    2097     1902263 :                 size_t index = ZEND_MM_BUCKET_INDEX(true_size);
    2098             :                 
    2099     1902263 :                 if (heap->cache[index] != NULL) {
    2100             :                         zend_mm_free_block *best_fit;
    2101             :                         zend_mm_free_block **cache;
    2102             : 
    2103             : #if ZEND_MM_CACHE_STAT
    2104             :                         heap->cache_stat[index].count--;
    2105             :                         heap->cache_stat[index].hit++;
    2106             : #endif
    2107     1644709 :                         best_fit = heap->cache[index];
    2108     1644709 :                         heap->cache[index] = best_fit->prev_free_block;
    2109             :                         ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
    2110             :                         ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
    2111             :         
    2112     1644709 :                         ptr = ZEND_MM_DATA_OF(best_fit);
    2113             : 
    2114             : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
    2115             :                         memcpy(ptr, p, mm_block->debug.size);
    2116             : #else
    2117     1644709 :                         memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
    2118             : #endif
    2119             : 
    2120     1644709 :                         heap->cached -= true_size - orig_size;
    2121             : 
    2122     1644709 :                         index = ZEND_MM_BUCKET_INDEX(orig_size);
    2123     1644709 :                         cache = &heap->cache[index];
    2124             : 
    2125     1644709 :                         ((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
    2126     1644709 :                         *cache = (zend_mm_free_block*)mm_block;
    2127             :                         ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
    2128             : #if ZEND_MM_CACHE_STAT
    2129             :                         if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
    2130             :                                 heap->cache_stat[index].max_count = heap->cache_stat[index].count;
    2131             :                         }
    2132             : #endif
    2133             : 
    2134     1644709 :                         return ptr;
    2135             :                 }
    2136             :         }
    2137             : #endif
    2138             : 
    2139     1321638 :         next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
    2140             : 
    2141     1321638 :         if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
    2142             :                 ZEND_MM_CHECK_COOKIE(next_block);
    2143     1045199 :                 ZEND_MM_CHECK_BLOCK_LINKAGE(next_block);
    2144     1045199 :                 if (orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block) >= true_size) {
    2145     1031959 :                         size_t block_size = orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block);
    2146     1031959 :                         size_t remaining_size = block_size - true_size;
    2147             : 
    2148     1031959 :                         HANDLE_BLOCK_INTERRUPTIONS();
    2149     1031959 :                         zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
    2150             : 
    2151     1031959 :                         if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
    2152       31068 :                                 true_size = block_size;
    2153       31068 :                                 ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2154             :                         } else {
    2155             :                                 zend_mm_free_block *new_free_block;
    2156             : 
    2157             :                                 /* prepare new free block */
    2158     1000891 :                                 ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2159     1000891 :                                 new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
    2160     1000891 :                                 ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
    2161             : 
    2162             :                                 /* add the new free block to the free list */
    2163     1078073 :                                 if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
    2164       41547 :                                     ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(new_free_block, remaining_size))) {
    2165       35635 :                                         zend_mm_add_to_rest_list(heap, new_free_block);
    2166             :                                 } else {
    2167      965256 :                                         zend_mm_add_to_free_list(heap, new_free_block);
    2168             :                                 }
    2169             :                         }
    2170             :                         ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
    2171     1031959 :                         heap->size = heap->size + true_size - orig_size;
    2172     1031959 :                         if (heap->peak < heap->size) {
    2173         863 :                                 heap->peak = heap->size;
    2174             :                         }
    2175     1031959 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    2176     1031959 :                         return p;
    2177       13252 :                 } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
    2178          12 :                                    ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(next_block, ZEND_MM_FREE_BLOCK_SIZE(next_block)))) {
    2179           0 :                         HANDLE_BLOCK_INTERRUPTIONS();
    2180           0 :                         zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
    2181           0 :                         goto realloc_segment;
    2182             :                 }
    2183      276439 :         } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && ZEND_MM_IS_GUARD_BLOCK(next_block)) {
    2184             :                 zend_mm_segment *segment;
    2185             :                 zend_mm_segment *segment_copy;
    2186             :                 size_t segment_size;
    2187             :                 size_t block_size;
    2188             :                 size_t remaining_size;
    2189             : 
    2190           0 :                 HANDLE_BLOCK_INTERRUPTIONS();
    2191             : realloc_segment:
    2192             :                 /* segment size, size of block and size of guard block */
    2193           0 :                 if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
    2194           0 :                         segment_size = true_size+ZEND_MM_ALIGNED_SEGMENT_SIZE+ZEND_MM_ALIGNED_HEADER_SIZE;
    2195           0 :                         segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
    2196             :                 } else {
    2197           0 :                         segment_size = heap->block_size;
    2198             :                 }
    2199             : 
    2200           0 :                 segment_copy = (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE);
    2201           0 :                 if (segment_size < true_size ||
    2202           0 :                     heap->real_size + segment_size - segment_copy->size > heap->limit) {
    2203           0 :                         if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
    2204           0 :                                 zend_mm_add_to_free_list(heap, (zend_mm_free_block *) next_block);
    2205             :                         }
    2206             : #if ZEND_MM_CACHE
    2207           0 :                         zend_mm_free_cache(heap);
    2208             : #endif
    2209           0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    2210             : #if ZEND_DEBUG
    2211             :                         zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted at %s:%d (tried to allocate %ld bytes)", heap->limit, __zend_filename, __zend_lineno, size);
    2212             : #else
    2213           0 :                         zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %ld bytes)", heap->limit, size);
    2214             : #endif
    2215           0 :                         return NULL;
    2216             :                 }
    2217             : 
    2218           0 :                 segment = ZEND_MM_STORAGE_REALLOC(segment_copy, segment_size);
    2219           0 :                 if (!segment) {
    2220             : #if ZEND_MM_CACHE
    2221           0 :                         zend_mm_free_cache(heap);
    2222             : #endif
    2223           0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    2224             : out_of_memory:
    2225             : #if ZEND_DEBUG
    2226             :                         zend_mm_safe_error(heap, "Out of memory (allocated %ld) at %s:%d (tried to allocate %ld bytes)", heap->real_size, __zend_filename, __zend_lineno, size);
    2227             : #else
    2228           0 :                         zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %ld bytes)", heap->real_size, size);
    2229             : #endif
    2230           0 :                         return NULL;
    2231             :                 }
    2232           0 :                 heap->real_size += segment_size - segment->size;
    2233           0 :                 if (heap->real_size > heap->real_peak) {
    2234           0 :                         heap->real_peak = heap->real_size;
    2235             :                 }
    2236             : 
    2237           0 :                 segment->size = segment_size;
    2238             : 
    2239           0 :                 if (segment != segment_copy) {
    2240           0 :                         zend_mm_segment **seg = &heap->segments_list;
    2241           0 :                         while (*seg != segment_copy) {
    2242           0 :                                 seg = &(*seg)->next_segment;
    2243             :                         }
    2244           0 :                         *seg = segment;
    2245           0 :                         mm_block = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    2246           0 :                         ZEND_MM_MARK_FIRST_BLOCK(mm_block);
    2247             :                 }
    2248             : 
    2249           0 :                 block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
    2250           0 :                 remaining_size = block_size - true_size;
    2251             : 
    2252             :                 /* setup guard block */
    2253           0 :                 ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(mm_block, block_size));
    2254             : 
    2255           0 :                 if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
    2256           0 :                         true_size = block_size;
    2257           0 :                         ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2258             :                 } else {
    2259             :                         zend_mm_free_block *new_free_block;
    2260             : 
    2261             :                         /* prepare new free block */
    2262           0 :                         ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2263           0 :                         new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
    2264           0 :                         ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
    2265             : 
    2266             :                         /* add the new free block to the free list */
    2267           0 :                         zend_mm_add_to_rest_list(heap, new_free_block);
    2268             :                 }
    2269             : 
    2270             :                 ZEND_MM_SET_DEBUG_INFO(mm_block, size, 1, 1);
    2271             : 
    2272           0 :                 heap->size = heap->size + true_size - orig_size;
    2273           0 :                 if (heap->peak < heap->size) {
    2274           0 :                         heap->peak = heap->size;
    2275             :                 }
    2276             : 
    2277           0 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
    2278           0 :                 return ZEND_MM_DATA_OF(mm_block);
    2279             :         }
    2280             : 
    2281      289679 :         ptr = _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2282             : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
    2283             :         memcpy(ptr, p, mm_block->debug.size);
    2284             : #else
    2285      289679 :         memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
    2286             : #endif
    2287      289679 :         _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2288      289679 :         return ptr;
    2289             : }
    2290             : 
    2291           0 : ZEND_API void *_zend_mm_alloc(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2292             : {
    2293           0 :         return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2294             : }
    2295             : 
    2296           0 : ZEND_API void _zend_mm_free(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2297             : {
    2298           0 :         _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2299           0 : }
    2300             : 
    2301           0 : ZEND_API void *_zend_mm_realloc(zend_mm_heap *heap, void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2302             : {
    2303           0 :         return _zend_mm_realloc_int(heap, ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2304             : }
    2305             : 
    2306           0 : ZEND_API size_t _zend_mm_block_size(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2307             : {
    2308             :         zend_mm_block *mm_block;
    2309             : 
    2310           0 :         if (!ZEND_MM_VALID_PTR(p)) {
    2311           0 :                 return 0;
    2312             :         }
    2313           0 :         mm_block = ZEND_MM_HEADER_OF(p);
    2314             :         ZEND_MM_CHECK_PROTECTION(mm_block);
    2315             : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
    2316             :         return mm_block->debug.size;
    2317             : #else
    2318           0 :         return ZEND_MM_BLOCK_SIZE(mm_block);
    2319             : #endif
    2320             : }
    2321             : 
    2322             : /**********************/
    2323             : /* Allocation Manager */
    2324             : /**********************/
    2325             : 
    2326             : typedef struct _zend_alloc_globals {
    2327             :         zend_mm_heap *mm_heap;
    2328             : } zend_alloc_globals;
    2329             : 
    2330             : #ifdef ZTS
    2331             : static int alloc_globals_id;
    2332             : # define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v)
    2333             : #else
    2334             : # define AG(v) (alloc_globals.v)
    2335             : static zend_alloc_globals alloc_globals;
    2336             : #endif
    2337             : 
    2338         138 : ZEND_API int is_zend_mm(TSRMLS_D)
    2339             : {
    2340         138 :         return AG(mm_heap)->use_zend_alloc;
    2341             : }
    2342             : 
    2343   187572804 : ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2344             : {
    2345             :         TSRMLS_FETCH();
    2346             : 
    2347   187572804 :         if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
    2348   133114435 :                 return AG(mm_heap)->_malloc(size);
    2349             :         }
    2350    54458369 :         return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2351             : }
    2352             : 
    2353   196698183 : ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2354             : {
    2355             :         TSRMLS_FETCH();
    2356             : 
    2357   196698183 :         if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
    2358   136140035 :                 AG(mm_heap)->_free(ptr);
    2359   136140035 :                 return;
    2360             :         }
    2361    60558148 :         _zend_mm_free_int(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2362             : }
    2363             : 
    2364    16234017 : ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2365             : {
    2366             :         TSRMLS_FETCH();
    2367             : 
    2368    16234017 :         if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
    2369     5085346 :                 return AG(mm_heap)->_realloc(ptr, size);
    2370             :         }
    2371    11148671 :         return _zend_mm_realloc_int(AG(mm_heap), ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2372             : }
    2373             : 
    2374           0 : ZEND_API size_t _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2375             : {
    2376           0 :         if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
    2377           0 :                 return 0;
    2378             :         }
    2379           0 :         return _zend_mm_block_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2380             : }
    2381             : 
    2382             : #if defined(__GNUC__) && defined(i386)
    2383             : 
    2384             : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
    2385             : {
    2386             :         size_t res = nmemb;
    2387             :         unsigned long overflow = 0;
    2388             : 
    2389             :         __asm__ ("mull %3\n\taddl %4,%0\n\tadcl $0,%1"
    2390             :              : "=&a"(res), "=&d" (overflow)
    2391             :              : "%0"(res),
    2392             :                "rm"(size),
    2393             :                "rm"(offset));
    2394             :         
    2395             :         if (UNEXPECTED(overflow)) {
    2396             :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
    2397             :                 return 0;
    2398             :         }
    2399             :         return res;
    2400             : }
    2401             : 
    2402             : #elif defined(__GNUC__) && defined(__x86_64__)
    2403             : 
    2404    12995370 : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
    2405             : {
    2406    12995370 :         size_t res = nmemb;
    2407    12995370 :         unsigned long overflow = 0;
    2408             : 
    2409    12995370 :         __asm__ ("mulq %3\n\taddq %4,%0\n\tadcq $0,%1"
    2410             :              : "=&a"(res), "=&d" (overflow)
    2411             :              : "%0"(res),
    2412             :                "rm"(size),
    2413             :                "rm"(offset));
    2414             : 
    2415    12995370 :         if (UNEXPECTED(overflow)) {
    2416           0 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
    2417             :                 return 0;
    2418             :         }
    2419    12995370 :         return res;
    2420             : }
    2421             : 
    2422             : #elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64)
    2423             : 
    2424             : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
    2425             : {
    2426             :         zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset;
    2427             : 
    2428             :         if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) {
    2429             :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
    2430             :                 return 0;
    2431             :         }
    2432             :         return (size_t) res;
    2433             : }
    2434             : 
    2435             : #else
    2436             : 
    2437             : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
    2438             : {
    2439             :         size_t res = nmemb * size + offset;
    2440             :         double _d  = (double)nmemb * (double)size + (double)offset;
    2441             :         double _delta = (double)res - _d;
    2442             : 
    2443             :         if (UNEXPECTED((_d + _delta ) != _d)) {
    2444             :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
    2445             :                 return 0;
    2446             :         }
    2447             :         return res;
    2448             : }
    2449             : #endif
    2450             : 
    2451             : 
    2452    12785629 : ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2453             : {
    2454    12785629 :         return emalloc_rel(safe_address(nmemb, size, offset));
    2455             : }
    2456             : 
    2457      207266 : ZEND_API void *_safe_malloc(size_t nmemb, size_t size, size_t offset)
    2458             : {
    2459      207266 :         return pemalloc(safe_address(nmemb, size, offset), 1);
    2460             : }
    2461             : 
    2462        2475 : ZEND_API void *_safe_erealloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2463             : {
    2464        2475 :         return erealloc_rel(ptr, safe_address(nmemb, size, offset));
    2465             : }
    2466             : 
    2467           0 : ZEND_API void *_safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset)
    2468             : {
    2469           0 :         return perealloc(ptr, safe_address(nmemb, size, offset), 1);
    2470             : }
    2471             : 
    2472             : 
    2473     9925791 : ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2474             : {
    2475             :         void *p;
    2476             : 
    2477     9925791 :         p = _safe_emalloc(nmemb, size, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2478     9925791 :         if (UNEXPECTED(p == NULL)) {
    2479           0 :                 return p;
    2480             :         }
    2481     9925791 :         memset(p, 0, size * nmemb);
    2482     9925791 :         return p;
    2483             : }
    2484             : 
    2485     2592124 : ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2486             : {
    2487             :         int length;
    2488             :         char *p;
    2489             : 
    2490     2592124 :         length = strlen(s)+1;
    2491     2592124 :         p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2492     2592124 :         if (UNEXPECTED(p == NULL)) {
    2493           0 :                 return p;
    2494             :         }
    2495     2592124 :         memcpy(p, s, length);
    2496     2592124 :         return p;
    2497             : }
    2498             : 
    2499    22956588 : ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2500             : {
    2501             :         char *p;
    2502             : 
    2503    22956588 :         p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2504    22956588 :         if (UNEXPECTED(p == NULL)) {
    2505           0 :                 return p;
    2506             :         }
    2507    22956588 :         memcpy(p, s, length);
    2508    22956588 :         p[length] = 0;
    2509    22956588 :         return p;
    2510             : }
    2511             : 
    2512             : 
    2513    54243406 : ZEND_API char *zend_strndup(const char *s, uint length)
    2514             : {
    2515             :         char *p;
    2516             : 
    2517    54243406 :         p = (char *) malloc(length+1);
    2518    54243406 :         if (UNEXPECTED(p == NULL)) {
    2519           0 :                 return p;
    2520             :         }
    2521    54243406 :         if (length) {
    2522    53760865 :                 memcpy(p, s, length);
    2523             :         }
    2524    54243406 :         p[length] = 0;
    2525    54243406 :         return p;
    2526             : }
    2527             : 
    2528             : 
    2529       19938 : ZEND_API int zend_set_memory_limit(size_t memory_limit)
    2530             : {
    2531             :         TSRMLS_FETCH();
    2532             : 
    2533       19938 :         AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size;
    2534             : 
    2535       19938 :         return SUCCESS;
    2536             : }
    2537             : 
    2538       23766 : ZEND_API size_t zend_memory_usage(int real_usage TSRMLS_DC)
    2539             : {
    2540       23766 :         if (real_usage) {
    2541        6482 :                 return AG(mm_heap)->real_size;
    2542             :         } else {
    2543       17284 :                 size_t usage = AG(mm_heap)->size;
    2544             : #if ZEND_MM_CACHE
    2545       17284 :                 usage -= AG(mm_heap)->cached;
    2546             : #endif
    2547       17284 :                 return usage;
    2548             :         }
    2549             : }
    2550             : 
    2551           1 : ZEND_API size_t zend_memory_peak_usage(int real_usage TSRMLS_DC)
    2552             : {
    2553           1 :         if (real_usage) {
    2554           0 :                 return AG(mm_heap)->real_peak;
    2555             :         } else {
    2556           1 :                 return AG(mm_heap)->peak;
    2557             :         }
    2558             : }
    2559             : 
    2560       58079 : ZEND_API void shutdown_memory_manager(int silent, int full_shutdown TSRMLS_DC)
    2561             : {
    2562       58079 :         zend_mm_shutdown(AG(mm_heap), full_shutdown, silent TSRMLS_CC);
    2563       58079 : }
    2564             : 
    2565       19341 : static void alloc_globals_ctor(zend_alloc_globals *alloc_globals TSRMLS_DC)
    2566             : {
    2567             :         char *tmp;
    2568       19341 :         alloc_globals->mm_heap = zend_mm_startup();
    2569             : 
    2570       19341 :         tmp = getenv("USE_ZEND_ALLOC");
    2571       19341 :         if (tmp) {
    2572       19333 :                 alloc_globals->mm_heap->use_zend_alloc = zend_atoi(tmp, 0);
    2573       19333 :                 if (!alloc_globals->mm_heap->use_zend_alloc) {
    2574       19333 :                         alloc_globals->mm_heap->_malloc = malloc;
    2575       19333 :                         alloc_globals->mm_heap->_free = free;
    2576       19333 :                         alloc_globals->mm_heap->_realloc = realloc;
    2577             :                 }
    2578             :         }
    2579       19341 : }
    2580             : 
    2581             : #ifdef ZTS
    2582             : static void alloc_globals_dtor(zend_alloc_globals *alloc_globals TSRMLS_DC)
    2583             : {
    2584             :         shutdown_memory_manager(1, 1 TSRMLS_CC);
    2585             : }
    2586             : #endif
    2587             : 
    2588       19341 : ZEND_API void start_memory_manager(TSRMLS_D)
    2589             : {
    2590             : #ifdef ZTS
    2591             :         ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor);
    2592             : #else
    2593       19341 :         alloc_globals_ctor(&alloc_globals);
    2594             : #endif
    2595       19341 : }
    2596             : 
    2597           0 : ZEND_API zend_mm_heap *zend_mm_set_heap(zend_mm_heap *new_heap TSRMLS_DC)
    2598             : {
    2599             :         zend_mm_heap *old_heap;
    2600             : 
    2601           0 :         old_heap = AG(mm_heap);
    2602           0 :         AG(mm_heap) = new_heap;
    2603           0 :         return old_heap;
    2604             : }
    2605             : 
    2606           0 : ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap)
    2607             : {
    2608           0 :         return heap->storage;
    2609             : }
    2610             : 
    2611           0 : ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
    2612             :                                           void* (*_malloc)(size_t),
    2613             :                                           void  (*_free)(void*),
    2614             :                                           void* (*_realloc)(void*, size_t))
    2615             : {
    2616           0 :         heap->use_zend_alloc = 0;
    2617           0 :         heap->_malloc = _malloc;
    2618           0 :         heap->_free = _free;
    2619           0 :         heap->_realloc = _realloc;
    2620           0 : }
    2621             : 
    2622             : #if ZEND_DEBUG
    2623             : ZEND_API int _mem_block_check(void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2624             : {
    2625             :         TSRMLS_FETCH();
    2626             : 
    2627             :         if (!AG(mm_heap)->use_zend_alloc) {
    2628             :                 return 1;
    2629             :         }
    2630             :         return zend_mm_check_ptr(AG(mm_heap), ptr, silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2631             : }
    2632             : 
    2633             : 
    2634             : ZEND_API void _full_mem_check(int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2635             : {
    2636             :         int errors;
    2637             :         TSRMLS_FETCH();
    2638             : 
    2639             :         if (!AG(mm_heap)->use_zend_alloc) {
    2640             :                 return;
    2641             :         }
    2642             : 
    2643             :         zend_debug_alloc_output("------------------------------------------------\n");
    2644             :         zend_debug_alloc_output("Full Memory Check at %s:%d\n" ZEND_FILE_LINE_RELAY_CC);
    2645             : 
    2646             :         errors = zend_mm_check_heap(AG(mm_heap), silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2647             : 
    2648             :         zend_debug_alloc_output("End of full memory check %s:%d (%d errors)\n" ZEND_FILE_LINE_RELAY_CC, errors);
    2649             :         zend_debug_alloc_output("------------------------------------------------\n");
    2650             : }
    2651             : #endif
    2652             : 
    2653             : /*
    2654             :  * Local variables:
    2655             :  * tab-width: 4
    2656             :  * c-basic-offset: 4
    2657             :  * indent-tabs-mode: t
    2658             :  * End:
    2659             :  */

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:23 +0000 (1 hour ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.