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

LTP GCOV extension - code coverage report
Current view: directory - var/php_gcov/PHP_5_2/Zend - zend_alloc.c
Test: PHP Code Coverage
Date: 2009-11-19 Instrumented lines: 679
Code covered: 65.8 % Executed lines: 447
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Thu, 19 Nov 2009 08:20:03 +0000 (5 days ago)

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