LTP GCOV extension - code coverage report
Current view: directory - Zend - zend_alloc.c
Test: PHP Code Coverage
Date: 2007-04-10 Instrumented lines: 654
Code covered: 63.9 % Executed lines: 418
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5