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_3/Zend - zend_alloc.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 693
Code covered: 71.0 % Executed lines: 492
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 287992 2009-09-03 14:33:11Z dmitry $ */
      22                 : 
      23                 : #include "zend.h"
      24                 : #include "zend_alloc.h"
      25                 : #include "zend_globals.h"
      26                 : #include "zend_operators.h"
      27                 : 
      28                 : #ifdef HAVE_SIGNAL_H
      29                 : # include <signal.h>
      30                 : #endif
      31                 : #ifdef HAVE_UNISTD_H
      32                 : # include <unistd.h>
      33                 : #endif
      34                 : 
      35                 : #ifdef ZEND_WIN32
      36                 : # include <wincrypt.h>
      37                 : # include <process.h>
      38                 : #endif
      39                 : 
      40                 : #ifndef ZEND_MM_HEAP_PROTECTION
      41                 : # define ZEND_MM_HEAP_PROTECTION ZEND_DEBUG
      42                 : #endif
      43                 : 
      44                 : #ifndef ZEND_MM_SAFE_UNLINKING
      45                 : # define ZEND_MM_SAFE_UNLINKING 1
      46                 : #endif
      47                 : 
      48                 : #ifndef ZEND_MM_COOKIES
      49                 : # define ZEND_MM_COOKIES ZEND_DEBUG
      50                 : #endif
      51                 : 
      52                 : #ifdef _WIN64
      53                 : # define PTR_FMT "0x%0.16I64x"
      54                 : /*
      55                 : #elif sizeof(long) == 8
      56                 : # define PTR_FMT "0x%0.16lx"
      57                 : */
      58                 : #else
      59                 : # define PTR_FMT "0x%0.8lx"
      60                 : #endif
      61                 : 
      62                 : #if ZEND_DEBUG
      63                 : void zend_debug_alloc_output(char *format, ...)
      64                 : {
      65                 :         char output_buf[256];
      66                 :         va_list args;
      67                 : 
      68                 :         va_start(args, format);
      69                 :         vsprintf(output_buf, format, args);
      70                 :         va_end(args);
      71                 : 
      72                 : #ifdef ZEND_WIN32
      73                 :         OutputDebugString(output_buf);
      74                 : #else
      75                 :         fprintf(stderr, "%s", output_buf);
      76                 : #endif
      77                 : }
      78                 : #endif
      79                 : 
      80                 : #if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
      81                 : static void zend_mm_panic(const char *message) __attribute__ ((noreturn));
      82                 : #endif
      83                 : 
      84                 : static void zend_mm_panic(const char *message)
      85               0 : {
      86               0 :         fprintf(stderr, "%s\n", message);
      87                 : #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID)
      88                 :         kill(getpid(), SIGSEGV);
      89                 : #endif
      90               0 :         exit(1);
      91                 : }
      92                 : 
      93                 : /*******************/
      94                 : /* Storage Manager */
      95                 : /*******************/
      96                 : 
      97                 : #ifdef ZEND_WIN32
      98                 : #  define HAVE_MEM_WIN32    /* use VirtualAlloc() to allocate memory     */
      99                 : #endif
     100                 : #define HAVE_MEM_MALLOC     /* use malloc() to allocate segments         */
     101                 : 
     102                 : #include <sys/types.h>
     103                 : #include <sys/stat.h>
     104                 : #if HAVE_LIMITS_H
     105                 : #include <limits.h>
     106                 : #endif
     107                 : #include <fcntl.h>
     108                 : #include <errno.h>
     109                 : 
     110                 : #if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
     111                 : # ifdef HAVE_MREMAP
     112                 : #  ifndef _GNU_SOURCE
     113                 : #   define _GNU_SOURCE
     114                 : #  endif
     115                 : #  ifndef __USE_GNU
     116                 : #   define __USE_GNU
     117                 : #  endif
     118                 : # endif
     119                 : # include <sys/mman.h>
     120                 : # ifndef MAP_ANON
     121                 : #  ifdef MAP_ANONYMOUS
     122                 : #   define MAP_ANON MAP_ANONYMOUS
     123                 : #  endif
     124                 : # endif
     125                 : # ifndef MREMAP_MAYMOVE
     126                 : #  define MREMAP_MAYMOVE 0
     127                 : # endif
     128                 : # ifndef MAP_FAILED
     129                 : #  define MAP_FAILED ((void*)-1)
     130                 : # endif
     131                 : #endif
     132                 : 
     133                 : static zend_mm_storage* zend_mm_mem_dummy_init(void *params)
     134           17633 : {
     135           17633 :         return malloc(sizeof(zend_mm_storage));
     136                 : }
     137                 : 
     138                 : static void zend_mm_mem_dummy_dtor(zend_mm_storage *storage)
     139           17665 : {
     140           17665 :         free(storage);
     141           17665 : }
     142                 : 
     143                 : static void zend_mm_mem_dummy_compact(zend_mm_storage *storage)
     144               1 : {
     145               1 : }
     146                 : 
     147                 : #if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
     148                 : 
     149                 : static zend_mm_segment* zend_mm_mem_mmap_realloc(zend_mm_storage *storage, zend_mm_segment* segment, size_t size)
     150               0 : {
     151                 :         zend_mm_segment *ret;
     152                 : #ifdef HAVE_MREMAP
     153                 : #if defined(__NetBSD__)
     154                 :         /* NetBSD 5 supports mremap but takes an extra newp argument */
     155                 :         ret = (zend_mm_segment*)mremap(segment, segment->size, segment, size, MREMAP_MAYMOVE);
     156                 : #else
     157               0 :         ret = (zend_mm_segment*)mremap(segment, segment->size, size, MREMAP_MAYMOVE);
     158                 : #endif
     159               0 :         if (ret == MAP_FAILED) {
     160                 : #endif
     161               0 :                 ret = storage->handlers->_alloc(storage, size);
     162               0 :                 if (ret) {
     163               0 :                         memcpy(ret, segment, size > segment->size ? segment->size : size);
     164               0 :                         storage->handlers->_free(storage, segment);
     165                 :                 }
     166                 : #ifdef HAVE_MREMAP
     167                 :         }
     168                 : #endif
     169               0 :         return ret;
     170                 : }
     171                 : 
     172                 : static void zend_mm_mem_mmap_free(zend_mm_storage *storage, zend_mm_segment* segment)
     173               0 : {
     174               0 :         munmap((void*)segment, segment->size);
     175               0 : }
     176                 : 
     177                 : #endif
     178                 : 
     179                 : #ifdef HAVE_MEM_MMAP_ANON
     180                 : 
     181                 : static zend_mm_segment* zend_mm_mem_mmap_anon_alloc(zend_mm_storage *storage, size_t size)
     182               0 : {
     183               0 :         zend_mm_segment *ret = (zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
     184               0 :         if (ret == MAP_FAILED) {
     185               0 :                 ret = NULL;
     186                 :         }
     187               0 :         return ret;
     188                 : }
     189                 : 
     190                 : # define ZEND_MM_MEM_MMAP_ANON_DSC {"mmap_anon", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_anon_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
     191                 : 
     192                 : #endif
     193                 : 
     194                 : #ifdef HAVE_MEM_MMAP_ZERO
     195                 : 
     196                 : static int zend_mm_dev_zero_fd = -1;
     197                 : 
     198                 : static zend_mm_storage* zend_mm_mem_mmap_zero_init(void *params)
     199               0 : {
     200               0 :         if (zend_mm_dev_zero_fd != -1) {
     201               0 :                 zend_mm_dev_zero_fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
     202                 :         }
     203               0 :         if (zend_mm_dev_zero_fd >= 0) {
     204               0 :                 return malloc(sizeof(zend_mm_storage));
     205                 :         } else {
     206               0 :                 return NULL;
     207                 :         }
     208                 : }
     209                 : 
     210                 : static void zend_mm_mem_mmap_zero_dtor(zend_mm_storage *storage)
     211               0 : {
     212               0 :         close(zend_mm_dev_zero_fd);
     213               0 :         free(storage);
     214               0 : }
     215                 : 
     216                 : static zend_mm_segment* zend_mm_mem_mmap_zero_alloc(zend_mm_storage *storage, size_t size)
     217               0 : {
     218               0 :         zend_mm_segment *ret = (zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zend_mm_dev_zero_fd, 0);
     219               0 :         if (ret == MAP_FAILED) {
     220               0 :                 ret = NULL;
     221                 :         }
     222               0 :         return ret;
     223                 : }
     224                 : 
     225                 : # define ZEND_MM_MEM_MMAP_ZERO_DSC {"mmap_zero", zend_mm_mem_mmap_zero_init, zend_mm_mem_mmap_zero_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_mmap_zero_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
     226                 : 
     227                 : #endif
     228                 : 
     229                 : #ifdef HAVE_MEM_WIN32
     230                 : 
     231                 : static zend_mm_storage* zend_mm_mem_win32_init(void *params)
     232                 : {
     233                 :         HANDLE heap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
     234                 :         zend_mm_storage* storage;
     235                 : 
     236                 :         if (heap == NULL) {
     237                 :                 return NULL;
     238                 :         }
     239                 :         storage = (zend_mm_storage*)malloc(sizeof(zend_mm_storage));
     240                 :         storage->data = (void*) heap;
     241                 :         return storage;
     242                 : }
     243                 : 
     244                 : static void zend_mm_mem_win32_dtor(zend_mm_storage *storage)
     245                 : {
     246                 :         HeapDestroy((HANDLE)storage->data);
     247                 :         free(storage);
     248                 : }
     249                 : 
     250                 : static void zend_mm_mem_win32_compact(zend_mm_storage *storage)
     251                 : {
     252                 :     HeapDestroy((HANDLE)storage->data);
     253                 :     storage->data = (void*)HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
     254                 : }
     255                 : 
     256                 : static zend_mm_segment* zend_mm_mem_win32_alloc(zend_mm_storage *storage, size_t size)
     257                 : {
     258                 :         return (zend_mm_segment*) HeapAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, size);
     259                 : }
     260                 : 
     261                 : static void zend_mm_mem_win32_free(zend_mm_storage *storage, zend_mm_segment* segment)
     262                 : {
     263                 :         HeapFree((HANDLE)storage->data, HEAP_NO_SERIALIZE, segment);
     264                 : }
     265                 : 
     266                 : static zend_mm_segment* zend_mm_mem_win32_realloc(zend_mm_storage *storage, zend_mm_segment* segment, size_t size)
     267                 : {
     268                 :         return (zend_mm_segment*) HeapReAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, segment, size);
     269                 : }
     270                 : 
     271                 : # define ZEND_MM_MEM_WIN32_DSC {"win32", zend_mm_mem_win32_init, zend_mm_mem_win32_dtor, zend_mm_mem_win32_compact, zend_mm_mem_win32_alloc, zend_mm_mem_win32_realloc, zend_mm_mem_win32_free}
     272                 : 
     273                 : #endif
     274                 : 
     275                 : #ifdef HAVE_MEM_MALLOC
     276                 : 
     277                 : static zend_mm_segment* zend_mm_mem_malloc_alloc(zend_mm_storage *storage, size_t size)
     278           58007 : {
     279           58007 :         return (zend_mm_segment*)malloc(size);
     280                 : }
     281                 : 
     282                 : static zend_mm_segment* zend_mm_mem_malloc_realloc(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size)
     283               1 : {
     284               1 :         return (zend_mm_segment*)realloc(ptr, size);
     285                 : }
     286                 : 
     287                 : static void zend_mm_mem_malloc_free(zend_mm_storage *storage, zend_mm_segment *ptr)
     288           58039 : {
     289           58039 :         free(ptr);
     290           58039 : }
     291                 : 
     292                 : # define ZEND_MM_MEM_MALLOC_DSC {"malloc", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_dummy_compact, zend_mm_mem_malloc_alloc, zend_mm_mem_malloc_realloc, zend_mm_mem_malloc_free}
     293                 : 
     294                 : #endif
     295                 : 
     296                 : static const zend_mm_mem_handlers mem_handlers[] = {
     297                 : #ifdef HAVE_MEM_WIN32
     298                 :         ZEND_MM_MEM_WIN32_DSC,
     299                 : #endif
     300                 : #ifdef HAVE_MEM_MALLOC
     301                 :         ZEND_MM_MEM_MALLOC_DSC,
     302                 : #endif
     303                 : #ifdef HAVE_MEM_MMAP_ANON
     304                 :         ZEND_MM_MEM_MMAP_ANON_DSC,
     305                 : #endif
     306                 : #ifdef HAVE_MEM_MMAP_ZERO
     307                 :         ZEND_MM_MEM_MMAP_ZERO_DSC,
     308                 : #endif
     309                 :         {NULL, NULL, NULL, NULL, NULL, NULL}
     310                 : };
     311                 : 
     312                 : # define ZEND_MM_STORAGE_DTOR()                                         heap->storage->handlers->dtor(heap->storage)
     313                 : # define ZEND_MM_STORAGE_ALLOC(size)                            heap->storage->handlers->_alloc(heap->storage, size)
     314                 : # define ZEND_MM_STORAGE_REALLOC(ptr, size)                     heap->storage->handlers->_realloc(heap->storage, ptr, size)
     315                 : # define ZEND_MM_STORAGE_FREE(ptr)                                      heap->storage->handlers->_free(heap->storage, ptr)
     316                 : 
     317                 : /****************/
     318                 : /* Heap Manager */
     319                 : /****************/
     320                 : 
     321                 : #define MEM_BLOCK_VALID  0x7312F8DC
     322                 : #define MEM_BLOCK_FREED  0x99954317
     323                 : #define MEM_BLOCK_CACHED 0xFB8277DC
     324                 : #define MEM_BLOCK_GUARD  0x2A8FCC84
     325                 : #define MEM_BLOCK_LEAK   0x6C5E8F2D
     326                 : 
     327                 : /* mm block type */
     328                 : typedef struct _zend_mm_block_info {
     329                 : #if ZEND_MM_COOKIES
     330                 :         size_t _cookie;
     331                 : #endif
     332                 :         size_t _size;
     333                 :         size_t _prev;
     334                 : } zend_mm_block_info;
     335                 : 
     336                 : #if ZEND_DEBUG
     337                 : 
     338                 : typedef struct _zend_mm_debug_info {
     339                 :         char *filename;
     340                 :         uint lineno;
     341                 :         char *orig_filename;
     342                 :         uint orig_lineno;
     343                 :         size_t size;
     344                 : #if ZEND_MM_HEAP_PROTECTION
     345                 :         unsigned int start_magic;
     346                 : #endif
     347                 : } zend_mm_debug_info;
     348                 : 
     349                 : #elif ZEND_MM_HEAP_PROTECTION
     350                 : 
     351                 : typedef struct _zend_mm_debug_info {
     352                 :         size_t size;
     353                 :         unsigned int start_magic;
     354                 : } zend_mm_debug_info;
     355                 : 
     356                 : #endif
     357                 : 
     358                 : typedef struct _zend_mm_block {
     359                 :         zend_mm_block_info info;
     360                 : #if ZEND_DEBUG
     361                 :         unsigned int magic;
     362                 : # ifdef ZTS
     363                 :         THREAD_T thread_id;
     364                 : # endif
     365                 :         zend_mm_debug_info debug;
     366                 : #elif ZEND_MM_HEAP_PROTECTION
     367                 :         zend_mm_debug_info debug;
     368                 : #endif
     369                 : } zend_mm_block;
     370                 : 
     371                 : typedef struct _zend_mm_small_free_block {
     372                 :         zend_mm_block_info info;
     373                 : #if ZEND_DEBUG
     374                 :         unsigned int magic;
     375                 : # ifdef ZTS
     376                 :         THREAD_T thread_id;
     377                 : # endif
     378                 : #endif
     379                 :         struct _zend_mm_free_block *prev_free_block;
     380                 :         struct _zend_mm_free_block *next_free_block;
     381                 : } zend_mm_small_free_block;
     382                 : 
     383                 : typedef struct _zend_mm_free_block {
     384                 :         zend_mm_block_info info;
     385                 : #if ZEND_DEBUG
     386                 :         unsigned int magic;
     387                 : # ifdef ZTS
     388                 :         THREAD_T thread_id;
     389                 : # endif
     390                 : #endif
     391                 :         struct _zend_mm_free_block *prev_free_block;
     392                 :         struct _zend_mm_free_block *next_free_block;
     393                 : 
     394                 :         struct _zend_mm_free_block **parent;
     395                 :         struct _zend_mm_free_block *child[2];
     396                 : } zend_mm_free_block;
     397                 : 
     398                 : #define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3)
     399                 : 
     400                 : #define ZEND_MM_CACHE 1
     401                 : #define ZEND_MM_CACHE_SIZE (ZEND_MM_NUM_BUCKETS * 4 * 1024)
     402                 : 
     403                 : #ifndef ZEND_MM_CACHE_STAT
     404                 : # define ZEND_MM_CACHE_STAT 0
     405                 : #endif
     406                 : 
     407                 : struct _zend_mm_heap {
     408                 :         int                 use_zend_alloc;
     409                 :         void               *(*_malloc)(size_t);
     410                 :         void                (*_free)(void*);
     411                 :         void               *(*_realloc)(void*, size_t);
     412                 :         size_t              free_bitmap;
     413                 :         size_t              large_free_bitmap;
     414                 :         size_t              block_size;
     415                 :         size_t              compact_size;
     416                 :         zend_mm_segment    *segments_list;
     417                 :         zend_mm_storage    *storage;
     418                 :         size_t              real_size;
     419                 :         size_t              real_peak;
     420                 :         size_t              limit;
     421                 :         size_t              size;
     422                 :         size_t              peak;
     423                 :         size_t              reserve_size;
     424                 :         void               *reserve;
     425                 :         int                 overflow;
     426                 :         int                 internal;
     427                 : #if ZEND_MM_CACHE
     428                 :         unsigned int        cached;
     429                 :         zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS];
     430                 : #endif
     431                 :         zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];
     432                 :         zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS];
     433                 :         zend_mm_free_block *rest_buckets[2];
     434                 : #if ZEND_MM_CACHE_STAT
     435                 :         struct {
     436                 :                 int count;
     437                 :                 int max_count;
     438                 :                 int hit;
     439                 :                 int miss;
     440                 :         } cache_stat[ZEND_MM_NUM_BUCKETS+1];
     441                 : #endif
     442                 : };
     443                 : 
     444                 : #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
     445                 :         (zend_mm_free_block*) ((char*)&heap->free_buckets[index * 2] + \
     446                 :                 sizeof(zend_mm_free_block*) * 2 - \
     447                 :                 sizeof(zend_mm_small_free_block))
     448                 : 
     449                 : #define ZEND_MM_REST_BUCKET(heap) \
     450                 :         (zend_mm_free_block*)((char*)&heap->rest_buckets[0] + \
     451                 :                 sizeof(zend_mm_free_block*) * 2 - \
     452                 :                 sizeof(zend_mm_small_free_block))
     453                 : 
     454                 : #if ZEND_MM_COOKIES
     455                 : 
     456                 : static unsigned int _zend_mm_cookie = 0;
     457                 : 
     458                 : # define ZEND_MM_COOKIE(block) \
     459                 :         (((size_t)(block)) ^ _zend_mm_cookie)
     460                 : # define ZEND_MM_SET_COOKIE(block) \
     461                 :         (block)->info._cookie = ZEND_MM_COOKIE(block)
     462                 : # define ZEND_MM_CHECK_COOKIE(block) \
     463                 :         if (UNEXPECTED((block)->info._cookie != ZEND_MM_COOKIE(block))) { \
     464                 :                 zend_mm_panic("zend_mm_heap corrupted"); \
     465                 :         }
     466                 : #else
     467                 : # define ZEND_MM_SET_COOKIE(block)
     468                 : # define ZEND_MM_CHECK_COOKIE(block)
     469                 : #endif
     470                 : 
     471                 : /* Default memory segment size */
     472                 : #define ZEND_MM_SEG_SIZE   (256 * 1024)
     473                 : 
     474                 : /* Reserved space for error reporting in case of memory overflow */
     475                 : #define ZEND_MM_RESERVE_SIZE            (8*1024)
     476                 : 
     477                 : #ifdef _WIN64
     478                 : # define ZEND_MM_LONG_CONST(x)  (x##i64)
     479                 : #else
     480                 : # define ZEND_MM_LONG_CONST(x)  (x##L)
     481                 : #endif
     482                 : 
     483                 : #define ZEND_MM_TYPE_MASK               ZEND_MM_LONG_CONST(0x3)
     484                 : 
     485                 : #define ZEND_MM_FREE_BLOCK              ZEND_MM_LONG_CONST(0x0)
     486                 : #define ZEND_MM_USED_BLOCK              ZEND_MM_LONG_CONST(0x1)
     487                 : #define ZEND_MM_GUARD_BLOCK             ZEND_MM_LONG_CONST(0x3)
     488                 : 
     489                 : #define ZEND_MM_BLOCK(b, type, size)    do { \
     490                 :                                                                                         size_t _size = (size); \
     491                 :                                                                                         (b)->info._size = (type) | _size; \
     492                 :                                                                                         ZEND_MM_BLOCK_AT(b, _size)->info._prev = (type) | _size; \
     493                 :                                                                                         ZEND_MM_SET_COOKIE(b); \
     494                 :                                                                                 } while (0);
     495                 : #define ZEND_MM_LAST_BLOCK(b)                   do { \
     496                 :                 (b)->info._size = ZEND_MM_GUARD_BLOCK | ZEND_MM_ALIGNED_HEADER_SIZE; \
     497                 :                 ZEND_MM_SET_MAGIC(b, MEM_BLOCK_GUARD); \
     498                 :         } while (0);
     499                 : #define ZEND_MM_BLOCK_SIZE(b)                   ((b)->info._size & ~ZEND_MM_TYPE_MASK)
     500                 : #define ZEND_MM_IS_FREE_BLOCK(b)                (!((b)->info._size & ZEND_MM_USED_BLOCK))
     501                 : #define ZEND_MM_IS_USED_BLOCK(b)                ((b)->info._size & ZEND_MM_USED_BLOCK)
     502                 : #define ZEND_MM_IS_GUARD_BLOCK(b)               (((b)->info._size & ZEND_MM_TYPE_MASK) == ZEND_MM_GUARD_BLOCK)
     503                 : 
     504                 : #define ZEND_MM_NEXT_BLOCK(b)                   ZEND_MM_BLOCK_AT(b, ZEND_MM_BLOCK_SIZE(b))
     505                 : #define ZEND_MM_PREV_BLOCK(b)                   ZEND_MM_BLOCK_AT(b, -(int)((b)->info._prev & ~ZEND_MM_TYPE_MASK))
     506                 : 
     507                 : #define ZEND_MM_PREV_BLOCK_IS_FREE(b)   (!((b)->info._prev & ZEND_MM_USED_BLOCK))
     508                 : 
     509                 : #define ZEND_MM_MARK_FIRST_BLOCK(b)             ((b)->info._prev = ZEND_MM_GUARD_BLOCK)
     510                 : #define ZEND_MM_IS_FIRST_BLOCK(b)               ((b)->info._prev == ZEND_MM_GUARD_BLOCK)
     511                 : 
     512                 : /* optimized access */
     513                 : #define ZEND_MM_FREE_BLOCK_SIZE(b)              (b)->info._size
     514                 : 
     515                 : /* Aligned header size */
     516                 : #define ZEND_MM_ALIGNED_HEADER_SIZE                     ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_block))
     517                 : #define ZEND_MM_ALIGNED_FREE_HEADER_SIZE        ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_small_free_block))
     518                 : #define ZEND_MM_MIN_ALLOC_BLOCK_SIZE            ZEND_MM_ALIGNED_SIZE(ZEND_MM_ALIGNED_HEADER_SIZE + END_MAGIC_SIZE)
     519                 : #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)
     520                 : #define ZEND_MM_ALIGNED_SEGMENT_SIZE            ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_segment))
     521                 : 
     522                 : #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)
     523                 : 
     524                 : #define ZEND_MM_MAX_SMALL_SIZE                          ((ZEND_MM_NUM_BUCKETS<<ZEND_MM_ALIGNMENT_LOG2)+ZEND_MM_ALIGNED_MIN_HEADER_SIZE)
     525                 : 
     526                 : #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)))
     527                 : 
     528                 : #define ZEND_MM_BUCKET_INDEX(true_size)         ((true_size>>ZEND_MM_ALIGNMENT_LOG2)-(ZEND_MM_ALIGNED_MIN_HEADER_SIZE>>ZEND_MM_ALIGNMENT_LOG2))
     529                 : 
     530                 : #define ZEND_MM_SMALL_SIZE(true_size)           (true_size < ZEND_MM_MAX_SMALL_SIZE)
     531                 : 
     532                 : /* Memory calculations */
     533                 : #define ZEND_MM_BLOCK_AT(blk, offset)   ((zend_mm_block *) (((char *) (blk))+(offset)))
     534                 : #define ZEND_MM_DATA_OF(p)                              ((void *) (((char *) (p))+ZEND_MM_ALIGNED_HEADER_SIZE))
     535                 : #define ZEND_MM_HEADER_OF(blk)                  ZEND_MM_BLOCK_AT(blk, -(int)ZEND_MM_ALIGNED_HEADER_SIZE)
     536                 : 
     537                 : /* Debug output */
     538                 : #if ZEND_DEBUG
     539                 : 
     540                 : # ifdef ZTS
     541                 : #  define ZEND_MM_SET_THREAD_ID(block) \
     542                 :         ((zend_mm_block*)(block))->thread_id = tsrm_thread_id()
     543                 : #  define ZEND_MM_BAD_THREAD_ID(block) ((block)->thread_id != tsrm_thread_id())
     544                 : # else
     545                 : #  define ZEND_MM_SET_THREAD_ID(block)
     546                 : #  define ZEND_MM_BAD_THREAD_ID(block) 0
     547                 : # endif
     548                 : 
     549                 : # define ZEND_MM_VALID_PTR(block) \
     550                 :         zend_mm_check_ptr(heap, block, 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC)
     551                 : 
     552                 : # define ZEND_MM_SET_MAGIC(block, val) do { \
     553                 :                 (block)->magic = (val); \
     554                 :         } while (0)
     555                 : 
     556                 : # define ZEND_MM_CHECK_MAGIC(block, val) do { \
     557                 :                 if ((block)->magic != (val)) { \
     558                 :                         zend_mm_panic("zend_mm_heap corrupted"); \
     559                 :                 } \
     560                 :         } while (0)
     561                 : 
     562                 : # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) do { \
     563                 :                 ((zend_mm_block*)(block))->debug.filename = __zend_filename; \
     564                 :                 ((zend_mm_block*)(block))->debug.lineno = __zend_lineno; \
     565                 :                 ((zend_mm_block*)(block))->debug.orig_filename = __zend_orig_filename; \
     566                 :                 ((zend_mm_block*)(block))->debug.orig_lineno = __zend_orig_lineno; \
     567                 :                 ZEND_MM_SET_BLOCK_SIZE(block, __size); \
     568                 :                 if (set_valid) { \
     569                 :                         ZEND_MM_SET_MAGIC(block, MEM_BLOCK_VALID); \
     570                 :                 } \
     571                 :                 if (set_thread) { \
     572                 :                         ZEND_MM_SET_THREAD_ID(block); \
     573                 :                 } \
     574                 :         } while (0)
     575                 : 
     576                 : #else
     577                 : 
     578                 : # define ZEND_MM_VALID_PTR(ptr) EXPECTED(ptr != NULL)
     579                 : 
     580                 : # define ZEND_MM_SET_MAGIC(block, val)
     581                 : 
     582                 : # define ZEND_MM_CHECK_MAGIC(block, val)
     583                 : 
     584                 : # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) ZEND_MM_SET_BLOCK_SIZE(block, __size)
     585                 : 
     586                 : #endif
     587                 : 
     588                 : 
     589                 : #if ZEND_MM_HEAP_PROTECTION
     590                 : 
     591                 : # define ZEND_MM_CHECK_PROTECTION(block) \
     592                 :         do { \
     593                 :                 if ((block)->debug.start_magic != _mem_block_start_magic || \
     594                 :                     memcmp(ZEND_MM_END_MAGIC_PTR(block), &_mem_block_end_magic, END_MAGIC_SIZE) != 0) { \
     595                 :                     zend_mm_panic("zend_mm_heap corrupted"); \
     596                 :                 } \
     597                 :         } while (0)
     598                 : 
     599                 : # define ZEND_MM_END_MAGIC_PTR(block) \
     600                 :         (((char*)(ZEND_MM_DATA_OF(block))) + ((zend_mm_block*)(block))->debug.size)
     601                 : 
     602                 : # define END_MAGIC_SIZE sizeof(unsigned int)
     603                 : 
     604                 : # define ZEND_MM_SET_BLOCK_SIZE(block, __size) do { \
     605                 :                 char *p; \
     606                 :                 ((zend_mm_block*)(block))->debug.size = (__size); \
     607                 :                 p = ZEND_MM_END_MAGIC_PTR(block); \
     608                 :                 ((zend_mm_block*)(block))->debug.start_magic = _mem_block_start_magic; \
     609                 :                 memcpy(p, &_mem_block_end_magic, END_MAGIC_SIZE); \
     610                 :         } while (0)
     611                 : 
     612                 : static unsigned int _mem_block_start_magic = 0;
     613                 : static unsigned int _mem_block_end_magic   = 0;
     614                 : 
     615                 : #else
     616                 : 
     617                 : # if ZEND_DEBUG
     618                 : #  define ZEND_MM_SET_BLOCK_SIZE(block, _size) \
     619                 :         ((zend_mm_block*)(block))->debug.size = (_size)
     620                 : # else
     621                 : #  define ZEND_MM_SET_BLOCK_SIZE(block, _size)
     622                 : # endif
     623                 : 
     624                 : # define ZEND_MM_CHECK_PROTECTION(block)
     625                 : 
     626                 : # define END_MAGIC_SIZE 0
     627                 : 
     628                 : #endif
     629                 : 
     630                 : #if ZEND_MM_SAFE_UNLINKING
     631                 : # define ZEND_MM_CHECK_BLOCK_LINKAGE(block) \
     632                 :         if (UNEXPECTED((block)->info._size != ZEND_MM_BLOCK_AT(block, ZEND_MM_FREE_BLOCK_SIZE(block))->info._prev) || \
     633                 :                 UNEXPECTED(!UNEXPECTED(ZEND_MM_IS_FIRST_BLOCK(block)) && \
     634                 :             UNEXPECTED(ZEND_MM_PREV_BLOCK(block)->info._size != (block)->info._prev))) { \
     635                 :             zend_mm_panic("zend_mm_heap corrupted"); \
     636                 :         }
     637                 : #define ZEND_MM_CHECK_TREE(block) \
     638                 :         if (UNEXPECTED(*((block)->parent) != (block))) { \
     639                 :                 zend_mm_panic("zend_mm_heap corrupted"); \
     640                 :         }
     641                 : #else
     642                 : # define ZEND_MM_CHECK_BLOCK_LINKAGE(block)
     643                 : # define ZEND_MM_CHECK_TREE(block)
     644                 : #endif
     645                 : 
     646                 : #define ZEND_MM_LARGE_BUCKET_INDEX(S) zend_mm_high_bit(S)
     647                 : 
     648                 : 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;
     649                 : static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
     650                 : static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
     651                 : 
     652                 : static inline unsigned int zend_mm_high_bit(size_t _size)
     653        22725601 : {
     654                 : #if defined(__GNUC__) && defined(i386)
     655                 :         unsigned int n;
     656                 : 
     657        22725601 :         __asm__("bsrl %1,%0\n\t" : "=r" (n) : "rm"  (_size));
     658        22725601 :         return n;
     659                 : #elif defined(__GNUC__) && defined(__x86_64__)
     660                 :         unsigned long n;
     661                 : 
     662                 :         __asm__("bsrq %1,%0\n\t" : "=r" (n) : "rm"  (_size));
     663                 :         return (unsigned int)n;
     664                 : #elif defined(_MSC_VER) && defined(_M_IX86)
     665                 :         __asm {
     666                 :                 bsr eax, _size
     667                 :         }
     668                 : #else
     669                 :         unsigned int n = 0;
     670                 :         while (_size != 0) {
     671                 :                 _size = _size >> 1;
     672                 :                 n++;
     673                 :         }
     674                 :         return n-1;
     675                 : #endif
     676                 : }
     677                 : 
     678                 : static inline unsigned int zend_mm_low_bit(size_t _size)
     679        22854758 : {
     680                 : #if defined(__GNUC__) && defined(i386)
     681                 :         unsigned int n;
     682                 : 
     683        22854758 :         __asm__("bsfl %1,%0\n\t" : "=r" (n) : "rm"  (_size));
     684        22854758 :         return n;
     685                 : #elif defined(__GNUC__) && defined(__x86_64__)
     686                 :         unsigned long n;
     687                 : 
     688                 :         __asm__("bsfq %1,%0\n\t" : "=r" (n) : "rm"  (_size));
     689                 :         return (unsigned int)n;
     690                 : #elif defined(_MSC_VER) && defined(_M_IX86)
     691                 :         __asm {
     692                 :                 bsf eax, _size
     693                 :    }
     694                 : #else
     695                 :         static const int offset[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
     696                 :         unsigned int n;
     697                 :         unsigned int index = 0;
     698                 : 
     699                 :         n = offset[_size & 15];
     700                 :         while (n == 4) {
     701                 :                 _size >>= 4;
     702                 :                 index += n;
     703                 :                 n = offset[_size & 15];
     704                 :         }
     705                 : 
     706                 :         return index + n;
     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           39956 : {
     712                 :         zend_mm_free_block *prev, *next;
     713                 : 
     714                 :         ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
     715                 : 
     716           39956 :         if (!ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block))) {
     717           39956 :                 mm_block->parent = NULL;
     718                 :         }
     719                 : 
     720           39956 :         prev = heap->rest_buckets[0];
     721           39956 :         next = prev->next_free_block;
     722           39956 :         mm_block->prev_free_block = prev;
     723           39956 :         mm_block->next_free_block = next;
     724           39956 :         prev->next_free_block = next->prev_free_block = mm_block;
     725           39956 : }
     726                 : 
     727                 : static inline void zend_mm_add_to_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
     728        32899321 : {
     729                 :         size_t size;
     730                 :         size_t index;
     731                 : 
     732                 :         ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
     733                 : 
     734        32899321 :         size = ZEND_MM_FREE_BLOCK_SIZE(mm_block);
     735        32899321 :         if (EXPECTED(!ZEND_MM_SMALL_SIZE(size))) {
     736                 :                 zend_mm_free_block **p;
     737                 : 
     738         9574259 :                 index = ZEND_MM_LARGE_BUCKET_INDEX(size);
     739         9574259 :                 p = &heap->large_free_buckets[index];
     740         9574259 :                 mm_block->child[0] = mm_block->child[1] = NULL;
     741         9574259 :                 if (!*p) {
     742         5744204 :                         *p = mm_block;
     743         5744204 :                         mm_block->parent = p;
     744         5744204 :                         mm_block->prev_free_block = mm_block->next_free_block = mm_block;
     745         5744204 :                         heap->large_free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
     746                 :                 } else {
     747                 :                         size_t m;
     748                 : 
     749         6376794 :                         for (m = size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
     750         6376794 :                                 zend_mm_free_block *prev = *p;
     751                 : 
     752         6376794 :                                 if (ZEND_MM_FREE_BLOCK_SIZE(prev) != size) {
     753         6089582 :                                         p = &prev->child[(m >> (ZEND_MM_NUM_BUCKETS-1)) & 1];
     754         6089582 :                                         if (!*p) {
     755         3542843 :                                                 *p = mm_block;
     756         3542843 :                                                 mm_block->parent = p;
     757         3542843 :                                                 mm_block->prev_free_block = mm_block->next_free_block = mm_block;
     758         3542843 :                                                 break;
     759                 :                                         }
     760                 :                                 } else {
     761          287212 :                                         zend_mm_free_block *next = prev->next_free_block;
     762                 : 
     763          287212 :                                         prev->next_free_block = next->prev_free_block = mm_block;
     764          287212 :                                         mm_block->next_free_block = next;
     765          287212 :                                         mm_block->prev_free_block = prev;
     766          287212 :                                         mm_block->parent = NULL;
     767          287212 :                                         break;
     768                 :                                 }
     769         2546739 :                         }
     770                 :                 }
     771                 :         } else {
     772                 :                 zend_mm_free_block *prev, *next;
     773                 : 
     774        23325062 :                 index = ZEND_MM_BUCKET_INDEX(size);
     775                 : 
     776        23325062 :                 prev = ZEND_MM_SMALL_FREE_BUCKET(heap, index);
     777        23325062 :                 if (prev->prev_free_block == prev) {
     778        10041783 :                         heap->free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
     779                 :                 }
     780        23325062 :                 next = prev->next_free_block;
     781                 : 
     782        23325062 :                 mm_block->prev_free_block = prev;
     783        23325062 :                 mm_block->next_free_block = next;
     784        23325062 :                 prev->next_free_block = next->prev_free_block = mm_block;
     785                 :         }
     786        32899321 : }
     787                 : 
     788                 : static inline void zend_mm_remove_from_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
     789        32882277 : {
     790        32882277 :         zend_mm_free_block *prev = mm_block->prev_free_block;
     791        32882277 :         zend_mm_free_block *next = mm_block->next_free_block;
     792                 : 
     793                 :         ZEND_MM_CHECK_MAGIC(mm_block, MEM_BLOCK_FREED);
     794                 : 
     795        32882277 :         if (EXPECTED(prev == mm_block)) {
     796                 :                 zend_mm_free_block **rp, **cp;
     797                 : 
     798                 : #if ZEND_MM_SAFE_UNLINKING
     799         9233526 :                 if (UNEXPECTED(next != mm_block)) {
     800               0 :                         zend_mm_panic("zend_mm_heap corrupted");
     801                 :                 }
     802                 : #endif
     803                 : 
     804         9233526 :                 rp = &mm_block->child[mm_block->child[1] != NULL];
     805         9233526 :                 prev = *rp;
     806         9233526 :                 if (EXPECTED(prev == NULL)) {
     807         7775679 :                         size_t index = ZEND_MM_LARGE_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
     808                 : 
     809         7775679 :                         ZEND_MM_CHECK_TREE(mm_block);
     810         7775679 :                         *mm_block->parent = NULL;
     811         7775679 :                         if (mm_block->parent == &heap->large_free_buckets[index]) {
     812         5691254 :                                 heap->large_free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
     813                 :                     }
     814                 :                 } else {
     815         3666524 :                         while (*(cp = &(prev->child[prev->child[1] != NULL])) != NULL) {
     816          750830 :                                 prev = *cp;
     817          750830 :                                 rp = cp;
     818                 :                         }
     819         1457847 :                         *rp = NULL;
     820                 : 
     821         1483061 : subst_block:
     822         1483061 :                         ZEND_MM_CHECK_TREE(mm_block);
     823         1483061 :                         *mm_block->parent = prev;
     824         1483061 :                         prev->parent = mm_block->parent;
     825         1483061 :                         if ((prev->child[0] = mm_block->child[0])) {
     826          715505 :                                 ZEND_MM_CHECK_TREE(prev->child[0]);
     827          715505 :                                 prev->child[0]->parent = &prev->child[0];
     828                 :                         }
     829         1483061 :                         if ((prev->child[1] = mm_block->child[1])) {
     830           92223 :                                 ZEND_MM_CHECK_TREE(prev->child[1]);
     831           92223 :                                 prev->child[1]->parent = &prev->child[1];
     832                 :                         }
     833                 :                 }
     834                 :         } else {
     835                 : 
     836                 : #if ZEND_MM_SAFE_UNLINKING
     837        23648751 :                 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        23648751 :                 prev->next_free_block = next;
     843        23648751 :                 next->prev_free_block = prev;
     844                 : 
     845        23648751 :                 if (EXPECTED(ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block)))) {
     846        23323732 :                         if (EXPECTED(prev == next)) {
     847        10041745 :                                 size_t index = ZEND_MM_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
     848                 : 
     849        10041745 :                                 if (EXPECTED(heap->free_buckets[index*2] == heap->free_buckets[index*2+1])) {
     850        10041745 :                                         heap->free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
     851                 :                                 }
     852                 :                         }
     853          325019 :                 } else if (UNEXPECTED(mm_block->parent != NULL)) {
     854           25214 :                         goto subst_block;
     855                 :                 }
     856                 :         }
     857        32882277 : }
     858                 : 
     859                 : static inline void zend_mm_init(zend_mm_heap *heap)
     860           52917 : {
     861                 :         zend_mm_free_block* p;
     862                 :         int i;
     863                 : 
     864           52917 :         heap->free_bitmap = 0;
     865           52917 :         heap->large_free_bitmap = 0;
     866                 : #if ZEND_MM_CACHE
     867           52917 :         heap->cached = 0;
     868           52917 :         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           52917 :         p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
     876         1746261 :         for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
     877         1693344 :                 p->next_free_block = p;
     878         1693344 :                 p->prev_free_block = p;
     879         1693344 :                 p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2);
     880         1693344 :                 heap->large_free_buckets[i] = NULL;
     881                 :         }
     882           52917 :         heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap);
     883           52917 : }
     884                 : 
     885                 : static void zend_mm_del_segment(zend_mm_heap *heap, zend_mm_segment *segment)
     886            5069 : {
     887            5069 :         zend_mm_segment **p = &heap->segments_list;
     888                 : 
     889           10280 :         while (*p != segment) {
     890             142 :                 p = &(*p)->next_segment;
     891                 :         }
     892            5069 :         *p = segment->next_segment;
     893            5069 :         heap->real_size -= segment->size;
     894            5069 :         ZEND_MM_STORAGE_FREE(segment);
     895            5069 : }
     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           17633 : {
     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           17633 :         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           17633 :         storage = handlers->init(params);
    1037           17633 :         if (!storage) {
    1038               0 :                 fprintf(stderr, "Cannot initialize zend_mm storage [%s]\n", handlers->name);
    1039               0 :                 exit(255);
    1040                 :         }
    1041           17633 :         storage->handlers = handlers;
    1042                 : 
    1043           17633 :         heap = malloc(sizeof(struct _zend_mm_heap));
    1044                 : 
    1045           17633 :         heap->storage = storage;
    1046           17633 :         heap->block_size = block_size;
    1047           17633 :         heap->compact_size = 0;
    1048           17633 :         heap->segments_list = NULL;
    1049           17633 :         zend_mm_init(heap);
    1050                 : # if ZEND_MM_CACHE_STAT
    1051                 :         memset(heap->cache_stat, 0, sizeof(heap->cache_stat));
    1052                 : # endif
    1053                 : 
    1054           17633 :         heap->use_zend_alloc = 1;
    1055           17633 :         heap->real_size = 0;
    1056           17633 :         heap->overflow = 0;
    1057           17633 :         heap->real_peak = 0;
    1058           17633 :         heap->limit = ZEND_MM_LONG_CONST(1)<<(ZEND_MM_NUM_BUCKETS-2);
    1059           17633 :         heap->size = 0;
    1060           17633 :         heap->peak = 0;
    1061           17633 :         heap->internal = internal;
    1062           17633 :         heap->reserve = NULL;
    1063           17633 :         heap->reserve_size = reserve_size;
    1064           17633 :         if (reserve_size > 0) {
    1065           17633 :                 heap->reserve = _zend_mm_alloc_int(heap, reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
    1066                 :         }
    1067           17633 :         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           17633 :         return heap;
    1099                 : }
    1100                 : 
    1101                 : ZEND_API zend_mm_heap *zend_mm_startup(void)
    1102           17633 : {
    1103                 :         int i;
    1104                 :         size_t seg_size;
    1105           17633 :         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           17633 :         if (mem_type == NULL) {
    1111           17633 :                 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           17633 :         handlers = &mem_handlers[i];
    1128                 : 
    1129           17633 :         tmp = getenv("ZEND_MM_SEG_SIZE");
    1130           17633 :         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           17633 :                 seg_size = ZEND_MM_SEG_SIZE;
    1141                 :         }
    1142                 : 
    1143           17633 :         heap = zend_mm_startup_ex(handlers, seg_size, ZEND_MM_RESERVE_SIZE, 0, NULL);
    1144           17633 :         if (heap) {
    1145           17633 :                 tmp = getenv("ZEND_MM_COMPACT");
    1146           17633 :                 if (tmp) {
    1147               0 :                         heap->compact_size = zend_atoi(tmp, 0);
    1148                 :                 } else {
    1149           17633 :                         heap->compact_size = 2 * 1024 * 1024;
    1150                 :                 }
    1151                 :         }
    1152           17633 :         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 TSRMLS_DC)
    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 TSRMLS_CC);
    1229                 :                                 zend_message_dispatcher(ZMSG_MEMORY_LEAK_DETECTED, &leak TSRMLS_CC);
    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 TSRMLS_CC);
    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 TSRMLS_CC);
    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                 :                 TSRMLS_FETCH();
    1273                 :                 
    1274                 :                 zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC);
    1275                 :                 zend_debug_alloc_output("---------------------------------------\n");
    1276                 :                 zend_debug_alloc_output("%s(%d) : Block "PTR_FMT" status:\n" ZEND_FILE_LINE_RELAY_CC, ptr);
    1277                 :                 if (__zend_orig_filename) {
    1278                 :                         zend_debug_alloc_output("%s(%d) : Actual location (location was relayed)\n" ZEND_FILE_LINE_ORIG_RELAY_CC);
    1279                 :                 }
    1280                 :                 if (!ptr) {
    1281                 :                         zend_debug_alloc_output("NULL\n");
    1282                 :                         zend_debug_alloc_output("---------------------------------------\n");
    1283                 :                         return 0;
    1284                 :                 }
    1285                 :         }
    1286                 : 
    1287                 :         if (!ptr) {
    1288                 :                 if (silent) {
    1289                 :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1290                 :                 }
    1291                 :         }
    1292                 : 
    1293                 :         p = ZEND_MM_HEADER_OF(ptr);
    1294                 : 
    1295                 : #ifdef ZTS
    1296                 :         if (ZEND_MM_BAD_THREAD_ID(p)) {
    1297                 :                 if (!silent) {
    1298                 :                         zend_debug_alloc_output("Invalid pointer: ((thread_id=0x%0.8X) != (expected=0x%0.8X))\n", (long)p->thread_id, (long)tsrm_thread_id());
    1299                 :                         had_problems = 1;
    1300                 :                 } else {
    1301                 :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1302                 :                 }
    1303                 :         }
    1304                 : #endif
    1305                 : 
    1306                 :         if (p->info._size != ZEND_MM_NEXT_BLOCK(p)->info._prev) {
    1307                 :                 if (!silent) {
    1308                 :                         zend_debug_alloc_output("Invalid pointer: ((size="PTR_FMT") != (next.prev="PTR_FMT"))\n", p->info._size, ZEND_MM_NEXT_BLOCK(p)->info._prev);
    1309                 :                         had_problems = 1;
    1310                 :                 } else {
    1311                 :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1312                 :                 }
    1313                 :         }
    1314                 :         if (p->info._prev != ZEND_MM_GUARD_BLOCK &&
    1315                 :             ZEND_MM_PREV_BLOCK(p)->info._size != p->info._prev) {
    1316                 :                 if (!silent) {
    1317                 :                         zend_debug_alloc_output("Invalid pointer: ((prev="PTR_FMT") != (prev.size="PTR_FMT"))\n", p->info._prev, ZEND_MM_PREV_BLOCK(p)->info._size);
    1318                 :                         had_problems = 1;
    1319                 :                 } else {
    1320                 :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1321                 :                 }
    1322                 :         }
    1323                 : 
    1324                 :         if (had_problems) {
    1325                 :                 zend_debug_alloc_output("---------------------------------------\n");
    1326                 :                 return 0;
    1327                 :         }
    1328                 : 
    1329                 :         if (!silent) {
    1330                 :                 zend_debug_alloc_output("%10s\t","Beginning:  ");
    1331                 :         }
    1332                 : 
    1333                 :         if (!ZEND_MM_IS_USED_BLOCK(p)) {
    1334                 :                 if (!silent) {
    1335                 :                         if (p->magic != MEM_BLOCK_FREED) {
    1336                 :                                 zend_debug_alloc_output("Freed (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
    1337                 :                         } else {
    1338                 :                                 zend_debug_alloc_output("Freed\n");
    1339                 :                         }
    1340                 :                         had_problems = 1;
    1341                 :                 } else {
    1342                 :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1343                 :                 }
    1344                 :         } else if (ZEND_MM_IS_GUARD_BLOCK(p)) {
    1345                 :                 if (!silent) {
    1346                 :                         if (p->magic != MEM_BLOCK_FREED) {
    1347                 :                                 zend_debug_alloc_output("Guard (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
    1348                 :                         } else {
    1349                 :                                 zend_debug_alloc_output("Guard\n");
    1350                 :                         }
    1351                 :                         had_problems = 1;
    1352                 :                 } else {
    1353                 :                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1354                 :                 }
    1355                 :         } else {
    1356                 :                 switch (p->magic) {
    1357                 :                         case MEM_BLOCK_VALID:
    1358                 :                         case MEM_BLOCK_LEAK:
    1359                 :                                 if (!silent) {
    1360                 :                                         zend_debug_alloc_output("OK (allocated on %s:%d, %d bytes)\n", p->debug.filename, p->debug.lineno, (int)p->debug.size);
    1361                 :                                 }
    1362                 :                                 break; /* ok */
    1363                 :                         case MEM_BLOCK_CACHED:
    1364                 :                                 if (!no_cache_notice) {
    1365                 :                                         if (!silent) {
    1366                 :                                                 zend_debug_alloc_output("Cached\n");
    1367                 :                                                 had_problems = 1;
    1368                 :                                         } else {
    1369                 :                                                 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1370                 :                                         }
    1371                 :                                 }
    1372                 :                         case MEM_BLOCK_FREED:
    1373                 :                                 if (!silent) {
    1374                 :                                         zend_debug_alloc_output("Freed (invalid)\n");
    1375                 :                                         had_problems = 1;
    1376                 :                                 } else {
    1377                 :                                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1378                 :                                 }
    1379                 :                                 break;
    1380                 :                         case MEM_BLOCK_GUARD:
    1381                 :                                 if (!silent) {
    1382                 :                                         zend_debug_alloc_output("Guard (invalid)\n");
    1383                 :                                         had_problems = 1;
    1384                 :                                 } else {
    1385                 :                                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1386                 :                                 }
    1387                 :                                 break;
    1388                 :                         default:
    1389                 :                                 if (!silent) {
    1390                 :                                         zend_debug_alloc_output("Unknown (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_VALID);
    1391                 :                                         had_problems = 1;
    1392                 :                                         valid_beginning = 0;
    1393                 :                                 } else {
    1394                 :                                         return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1395                 :                                 }
    1396                 :                                 break;
    1397                 :                 }
    1398                 :         }
    1399                 : 
    1400                 : #if ZEND_MM_HEAP_PROTECTION
    1401                 :         if (!valid_beginning) {
    1402                 :                 if (!silent) {
    1403                 :                         zend_debug_alloc_output("%10s\t", "Start:");
    1404                 :                         zend_debug_alloc_output("Unknown\n");
    1405                 :                         zend_debug_alloc_output("%10s\t", "End:");
    1406                 :                         zend_debug_alloc_output("Unknown\n");
    1407                 :                 }
    1408                 :         } else {
    1409                 :                 char *end_magic = ZEND_MM_END_MAGIC_PTR(p);
    1410                 : 
    1411                 :                 if (p->debug.start_magic == _mem_block_start_magic) {
    1412                 :                         if (!silent) {
    1413                 :                                 zend_debug_alloc_output("%10s\t", "Start:");
    1414                 :                                 zend_debug_alloc_output("OK\n");
    1415                 :                         }
    1416                 :                 } else {
    1417                 :                         char *overflow_ptr, *magic_ptr=(char *) &_mem_block_start_magic;
    1418                 :                         int overflows=0;
    1419                 :                         int i;
    1420                 : 
    1421                 :                         if (silent) {
    1422                 :                                 return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1423                 :                         }
    1424                 :                         had_problems = 1;
    1425                 :                         overflow_ptr = (char *) &p->debug.start_magic;
    1426                 :                         i = END_MAGIC_SIZE;
    1427                 :                         while (--i >= 0) {
    1428                 :                                 if (overflow_ptr[i]!=magic_ptr[i]) {
    1429                 :                                         overflows++;
    1430                 :                                 }
    1431                 :                         }
    1432                 :                         zend_debug_alloc_output("%10s\t", "Start:");
    1433                 :                         zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", p->debug.start_magic, _mem_block_start_magic);
    1434                 :                         zend_debug_alloc_output("%10s\t","");
    1435                 :                         if (overflows >= END_MAGIC_SIZE) {
    1436                 :                                 zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
    1437                 :                         } else {
    1438                 :                                 zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
    1439                 :                         }
    1440                 :                 }
    1441                 :                 if (memcmp(end_magic, &_mem_block_end_magic, END_MAGIC_SIZE)==0) {
    1442                 :                         if (!silent) {
    1443                 :                                 zend_debug_alloc_output("%10s\t", "End:");
    1444                 :                                 zend_debug_alloc_output("OK\n");
    1445                 :                         }
    1446                 :                 } else {
    1447                 :                         char *overflow_ptr, *magic_ptr=(char *) &_mem_block_end_magic;
    1448                 :                         int overflows=0;
    1449                 :                         int i;
    1450                 : 
    1451                 :                         if (silent) {
    1452                 :                                 return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    1453                 :                         }
    1454                 :                         had_problems = 1;
    1455                 :                         overflow_ptr = (char *) end_magic;
    1456                 : 
    1457                 :                         for (i=0; i < END_MAGIC_SIZE; i++) {
    1458                 :                                 if (overflow_ptr[i]!=magic_ptr[i]) {
    1459                 :                                         overflows++;
    1460                 :                                 }
    1461                 :                         }
    1462                 : 
    1463                 :                         zend_debug_alloc_output("%10s\t", "End:");
    1464                 :                         zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", *end_magic, _mem_block_end_magic);
    1465                 :                         zend_debug_alloc_output("%10s\t","");
    1466                 :                         if (overflows >= END_MAGIC_SIZE) {
    1467                 :                                 zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
    1468                 :                         } else {
    1469                 :                                 zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
    1470                 :                         }
    1471                 :                 }
    1472                 :         }
    1473                 : #endif
    1474                 : 
    1475                 :         if (!silent) {
    1476                 :                 zend_debug_alloc_output("---------------------------------------\n");
    1477                 :         }
    1478                 :         return ((!had_problems) ? 1 : 0);
    1479                 : }
    1480                 : 
    1481                 : static int zend_mm_check_heap(zend_mm_heap *heap, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    1482                 : {
    1483                 :         zend_mm_segment *segment = heap->segments_list;
    1484                 :         zend_mm_block *p, *q;
    1485                 :         int errors = 0;
    1486                 : 
    1487                 :         if (!segment) {
    1488                 :                 return 0;
    1489                 :         }
    1490                 :         p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1491                 :         while (1) {
    1492                 :                 q = ZEND_MM_NEXT_BLOCK(p);
    1493                 :                 if (q <= p ||
    1494                 :                     (char*)q > (char*)segment + segment->size ||
    1495                 :                     p->info._size != q->info._prev) {
    1496                 :                         zend_mm_panic("zend_mm_heap corrupted");
    1497                 :                 }
    1498                 :                 if (!ZEND_MM_IS_FREE_BLOCK(p)) {
    1499                 :                         if (p->magic == MEM_BLOCK_VALID || p->magic == MEM_BLOCK_LEAK) {
    1500                 :                                 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)) {
    1501                 :                                         errors++;
    1502                 :                                 }
    1503                 : #if ZEND_MM_CACHE
    1504                 :                         } else if (p->magic == MEM_BLOCK_CACHED) {
    1505                 :                                 /* skip it */
    1506                 : #endif
    1507                 :                         } else if (p->magic != MEM_BLOCK_LEAK) {
    1508                 :                                 zend_mm_panic("zend_mm_heap corrupted");
    1509                 :                         }
    1510                 :                 }
    1511                 :                 if (ZEND_MM_IS_GUARD_BLOCK(q)) {
    1512                 :                         segment = segment->next_segment;
    1513                 :                         if (!segment) {
    1514                 :                                 return errors;
    1515                 :                         }
    1516                 :                         q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1517                 :                 }
    1518                 :                 p = q;
    1519                 :         }
    1520                 : }
    1521                 : #endif
    1522                 : 
    1523                 : ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, int full_shutdown, int silent TSRMLS_DC)
    1524           52949 : {
    1525                 :         zend_mm_storage *storage;
    1526                 :         zend_mm_segment *segment;
    1527                 :         zend_mm_segment *prev;
    1528                 :         int internal;
    1529                 : 
    1530           52949 :         if (heap->reserve) {
    1531                 : #if ZEND_DEBUG
    1532                 :                 if (!silent) {
    1533                 :                         _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
    1534                 :                 }
    1535                 : #endif
    1536           52949 :                 heap->reserve = NULL;
    1537                 :         }
    1538                 : 
    1539                 : #if ZEND_MM_CACHE_STAT
    1540                 :         if (full_shutdown) {
    1541                 :                 FILE *f;
    1542                 : 
    1543                 :                 f = fopen("zend_mm.log", "w");
    1544                 :                 if (f) {
    1545                 :                         int i,j;
    1546                 :                         size_t size, true_size, min_size, max_size;
    1547                 :                         int hit = 0, miss = 0;
    1548                 : 
    1549                 :                         fprintf(f, "\nidx min_size max_size true_size  max_len     hits   misses\n");
    1550                 :                         size = 0;
    1551                 :                         while (1) {
    1552                 :                                 true_size = ZEND_MM_TRUE_SIZE(size);
    1553                 :                                 if (ZEND_MM_SMALL_SIZE(true_size)) {
    1554                 :                                         min_size = size;
    1555                 :                                         i = ZEND_MM_BUCKET_INDEX(true_size);
    1556                 :                                         size++;
    1557                 :                                         while (1) {
    1558                 :                                                 true_size = ZEND_MM_TRUE_SIZE(size);
    1559                 :                                                 if (ZEND_MM_SMALL_SIZE(true_size)) {
    1560                 :                                                         j = ZEND_MM_BUCKET_INDEX(true_size);
    1561                 :                                                         if (j > i) {
    1562                 :                                                                 max_size = size-1;
    1563                 :                                                                 break;
    1564                 :                                                         }
    1565                 :                                                 } else {
    1566                 :                                                         max_size = size-1;
    1567                 :                                                         break;
    1568                 :                                                 }
    1569                 :                                                 size++;
    1570                 :                                         }
    1571                 :                                         hit += heap->cache_stat[i].hit;
    1572                 :                                         miss += heap->cache_stat[i].miss;
    1573                 :                                         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);
    1574                 :                                 } else {
    1575                 :                                         break;
    1576                 :                                 }
    1577                 :                         }
    1578                 :                         fprintf(f, "                                        %8d %8d\n", hit, miss);
    1579                 :                         fprintf(f, "                                        %8d %8d\n", heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit, heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss);
    1580                 :                         fclose(f);
    1581                 :                 }
    1582                 :         }
    1583                 : #endif
    1584                 : 
    1585                 : #if ZEND_DEBUG
    1586                 :         if (!silent) {
    1587                 :                 zend_mm_check_leaks(heap TSRMLS_CC);
    1588                 :         }
    1589                 : #endif
    1590                 : 
    1591           52949 :         internal = heap->internal;
    1592           52949 :         storage = heap->storage;
    1593           52949 :         segment = heap->segments_list;
    1594          158868 :         while (segment) {
    1595           52970 :                 prev = segment;
    1596           52970 :                 segment = segment->next_segment;
    1597           52970 :                 ZEND_MM_STORAGE_FREE(prev);
    1598                 :         }
    1599           52949 :         if (full_shutdown) {
    1600           17665 :                 storage->handlers->dtor(storage);
    1601           17665 :                 if (!internal) {
    1602           17665 :                         free(heap);
    1603                 :                 }
    1604                 :         } else {
    1605           35284 :                 if (heap->compact_size &&
    1606                 :                     heap->real_peak > heap->compact_size) {
    1607               1 :                         storage->handlers->compact(storage);
    1608                 :                 }
    1609           35284 :                 heap->segments_list = NULL;
    1610           35284 :                 zend_mm_init(heap);
    1611           35284 :                 heap->real_size = 0;
    1612           35284 :                 heap->real_peak = 0;
    1613           35284 :                 heap->size = 0;
    1614           35284 :                 heap->peak = 0;
    1615           35284 :                 if (heap->reserve_size) {
    1616           35284 :                         heap->reserve = _zend_mm_alloc_int(heap, heap->reserve_size  ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
    1617                 :                 }
    1618           35284 :                 heap->overflow = 0;
    1619                 :         }
    1620           52949 : }
    1621                 : 
    1622                 : static void zend_mm_safe_error(zend_mm_heap *heap,
    1623                 :         const char *format,
    1624                 :         size_t limit,
    1625                 : #if ZEND_DEBUG
    1626                 :         const char *filename,
    1627                 :         uint lineno,
    1628                 : #endif
    1629                 :         size_t size)
    1630               0 : {
    1631               0 :         if (heap->reserve) {
    1632               0 :                 _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
    1633               0 :                 heap->reserve = NULL;
    1634                 :         }
    1635               0 :         if (heap->overflow == 0) {
    1636                 :                 char *error_filename;
    1637                 :                 uint error_lineno;
    1638                 :                 TSRMLS_FETCH();
    1639               0 :                 if (zend_is_compiling(TSRMLS_C)) {
    1640               0 :                         error_filename = zend_get_compiled_filename(TSRMLS_C);
    1641               0 :                         error_lineno = zend_get_compiled_lineno(TSRMLS_C);
    1642               0 :                 } else if (EG(in_execution)) {
    1643               0 :                         error_filename = EG(active_op_array)?EG(active_op_array)->filename:NULL;
    1644               0 :                         error_lineno = EG(opline_ptr)?(*EG(opline_ptr))->lineno:0;
    1645                 :                 } else {
    1646               0 :                         error_filename = NULL;
    1647               0 :                         error_lineno = 0;
    1648                 :                 }
    1649               0 :                 if (!error_filename) {
    1650               0 :                         error_filename = "Unknown";
    1651                 :                 }
    1652               0 :                 heap->overflow = 1;
    1653               0 :                 zend_try {
    1654               0 :                         zend_error_noreturn(E_ERROR,
    1655                 :                                 format,
    1656                 :                                 limit,
    1657                 : #if ZEND_DEBUG
    1658                 :                                 filename,
    1659                 :                                 lineno,
    1660                 : #endif
    1661                 :                                 size);
    1662               0 :                 } zend_catch {
    1663               0 :                         if (heap->overflow == 2) {
    1664               0 :                                 fprintf(stderr, "\nFatal error: ");
    1665               0 :                                 fprintf(stderr,
    1666                 :                                         format,
    1667                 :                                         limit,
    1668                 : #if ZEND_DEBUG
    1669                 :                                         filename,
    1670                 :                                         lineno,
    1671                 : #endif
    1672                 :                                         size);
    1673               0 :                                 fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno);
    1674                 :                         }
    1675               0 :                 } zend_end_try();
    1676                 :         } else {
    1677               0 :                 heap->overflow = 2;
    1678                 :         }
    1679               0 :         zend_bailout();
    1680               0 : }
    1681                 : 
    1682                 : static zend_mm_free_block *zend_mm_search_large_block(zend_mm_heap *heap, size_t true_size)
    1683         5358030 : {
    1684                 :         zend_mm_free_block *best_fit;
    1685         5358030 :         size_t index = ZEND_MM_LARGE_BUCKET_INDEX(true_size);
    1686         5358030 :         size_t bitmap = heap->large_free_bitmap >> index;
    1687                 :         zend_mm_free_block *p;
    1688                 : 
    1689         5358030 :         if (bitmap == 0) {
    1690           57701 :                 return NULL;
    1691                 :         }
    1692                 : 
    1693         5300329 :         if (UNEXPECTED((bitmap & 1) != 0)) {
    1694                 :                 /* Search for best "large" free block */
    1695         1209226 :                 zend_mm_free_block *rst = NULL;
    1696                 :                 size_t m;
    1697         1209226 :                 size_t best_size = -1;
    1698                 : 
    1699         1209226 :                 best_fit = NULL;
    1700         1209226 :                 p = heap->large_free_buckets[index];
    1701         1764296 :                 for (m = true_size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
    1702         1764296 :                         if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
    1703          428202 :                                 return p->next_free_block;
    1704         1336094 :                         } else if (ZEND_MM_FREE_BLOCK_SIZE(p) >= true_size &&
    1705                 :                                    ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
    1706          543857 :                                 best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
    1707          543857 :                                 best_fit = p;
    1708                 :                         }
    1709         1336094 :                         if ((m & (ZEND_MM_LONG_CONST(1) << (ZEND_MM_NUM_BUCKETS-1))) == 0) {
    1710          632234 :                                 if (p->child[1]) {
    1711          153880 :                                         rst = p->child[1];
    1712                 :                                 }
    1713          632234 :                                 if (p->child[0]) {
    1714          267957 :                                         p = p->child[0];
    1715                 :                                 } else {
    1716          364277 :                                         break;
    1717                 :                                 }
    1718          703860 :                         } else if (p->child[1]) {
    1719          287113 :                                 p = p->child[1];
    1720                 :                         } else {
    1721          416747 :                                 break;
    1722                 :                         }
    1723          555070 :                 }
    1724                 : 
    1725          894298 :                 for (p = rst; p; p = p->child[p->child[0] != NULL]) {
    1726          113274 :                         if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
    1727               0 :                                 return p->next_free_block;
    1728          113274 :                         } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
    1729                 :                                    ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
    1730           40819 :                                 best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
    1731           40819 :                                 best_fit = p;
    1732                 :                         }
    1733                 :                 }
    1734                 : 
    1735          781024 :                 if (best_fit) {
    1736          396406 :                         return best_fit->next_free_block;
    1737                 :                 }
    1738          384618 :                 bitmap = bitmap >> 1;
    1739          384618 :                 if (!bitmap) {
    1740             306 :                         return NULL;
    1741                 :                 }
    1742          384312 :                 index++;
    1743                 :         }
    1744                 : 
    1745                 :         /* Search for smallest "large" free block */
    1746         4475415 :         best_fit = p = heap->large_free_buckets[index + zend_mm_low_bit(bitmap)];
    1747         9218750 :         while ((p = p->child[p->child[0] != NULL])) {
    1748          267920 :                 if (ZEND_MM_FREE_BLOCK_SIZE(p) < ZEND_MM_FREE_BLOCK_SIZE(best_fit)) {
    1749           80887 :                         best_fit = p;
    1750                 :                 }
    1751                 :         }
    1752         4475415 :         return best_fit->next_free_block;
    1753                 : }
    1754                 : 
    1755                 : static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    1756        61674044 : {
    1757                 :         zend_mm_free_block *best_fit;
    1758        61674044 :         size_t true_size = ZEND_MM_TRUE_SIZE(size);
    1759                 :         size_t block_size;
    1760                 :         size_t remaining_size;
    1761                 :         size_t segment_size;
    1762                 :         zend_mm_segment *segment;
    1763        61674044 :         int keep_rest = 0;
    1764                 : 
    1765        61674044 :         if (EXPECTED(ZEND_MM_SMALL_SIZE(true_size))) {
    1766        59891556 :                 size_t index = ZEND_MM_BUCKET_INDEX(true_size);
    1767                 :                 size_t bitmap;
    1768                 : 
    1769        59891556 :                 if (UNEXPECTED(true_size < size)) {
    1770               0 :                         goto out_of_memory;
    1771                 :                 }
    1772                 : #if ZEND_MM_CACHE
    1773        59891556 :                 if (EXPECTED(heap->cache[index] != NULL)) {
    1774                 :                         /* Get block from cache */
    1775                 : #if ZEND_MM_CACHE_STAT
    1776                 :                         heap->cache_stat[index].count--;
    1777                 :                         heap->cache_stat[index].hit++;
    1778                 : #endif
    1779        37954304 :                         best_fit = heap->cache[index];
    1780        37954304 :                         heap->cache[index] = best_fit->prev_free_block;
    1781        37954304 :                         heap->cached -= true_size;
    1782                 :                         ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
    1783                 :                         ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
    1784        37954304 :                         return ZEND_MM_DATA_OF(best_fit);
    1785                 :                 }
    1786                 : #if ZEND_MM_CACHE_STAT
    1787                 :                 heap->cache_stat[index].miss++;
    1788                 : #endif
    1789                 : #endif
    1790                 : 
    1791        21937252 :                 bitmap = heap->free_bitmap >> index;
    1792        21937252 :                 if (bitmap) {
    1793                 :                         /* Found some "small" free block that can be used */
    1794        18361710 :                         index += zend_mm_low_bit(bitmap);
    1795        18361710 :                         best_fit = heap->free_buckets[index*2];
    1796                 : #if ZEND_MM_CACHE_STAT
    1797                 :                         heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit++;
    1798                 : #endif
    1799        18361710 :                         goto zend_mm_finished_searching_for_block;
    1800                 :                 }
    1801                 :         }
    1802                 : 
    1803                 : #if ZEND_MM_CACHE_STAT
    1804                 :         heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss++;
    1805                 : #endif
    1806                 : 
    1807         5358030 :         best_fit = zend_mm_search_large_block(heap, true_size);
    1808                 : 
    1809         5358030 :         if (!best_fit && heap->real_size >= heap->limit - heap->block_size) {
    1810               0 :                 zend_mm_free_block *p = heap->rest_buckets[0];
    1811               0 :                 size_t best_size = -1;
    1812                 : 
    1813               0 :                 while (p != ZEND_MM_REST_BUCKET(heap)) {
    1814               0 :                         if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
    1815               0 :                                 best_fit = p;
    1816               0 :                                 goto zend_mm_finished_searching_for_block;
    1817               0 :                         } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
    1818                 :                                    ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
    1819               0 :                                 best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
    1820               0 :                                 best_fit = p;
    1821                 :                         }
    1822               0 :                         p = p->prev_free_block;
    1823                 :                 }
    1824                 :         }
    1825                 : 
    1826         5358030 :         if (!best_fit) {
    1827           58007 :                 if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
    1828                 :                         /* Make sure we add a memory block which is big enough,
    1829                 :                            segment must have header "size" and trailer "guard" block */
    1830               5 :                         segment_size = true_size + ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE;
    1831               5 :                         segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
    1832               5 :                         keep_rest = 1;
    1833                 :                 } else {
    1834           58002 :                         segment_size = heap->block_size;
    1835                 :                 }
    1836                 : 
    1837           58007 :                 HANDLE_BLOCK_INTERRUPTIONS();
    1838                 : 
    1839           58007 :                 if (segment_size < true_size ||
    1840                 :                     heap->real_size + segment_size > heap->limit) {
    1841                 :                         /* Memory limit overflow */
    1842                 : #if ZEND_MM_CACHE
    1843               0 :                         zend_mm_free_cache(heap);
    1844                 : #endif
    1845               0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    1846                 : #if ZEND_DEBUG
    1847                 :                         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);
    1848                 : #else
    1849               0 :                         zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %lu bytes)", heap->limit, size);
    1850                 : #endif
    1851                 :                 }
    1852                 : 
    1853           58007 :                 segment = (zend_mm_segment *) ZEND_MM_STORAGE_ALLOC(segment_size);
    1854                 : 
    1855           58007 :                 if (!segment) {
    1856                 :                         /* Storage manager cannot allocate memory */
    1857                 : #if ZEND_MM_CACHE
    1858               0 :                         zend_mm_free_cache(heap);
    1859                 : #endif
    1860               0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    1861               0 : out_of_memory:
    1862                 : #if ZEND_DEBUG
    1863                 :                         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);
    1864                 : #else
    1865               0 :                         zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %lu bytes)", heap->real_size, size);
    1866                 : #endif
    1867               0 :                         return NULL;
    1868                 :                 }
    1869                 : 
    1870           58007 :                 heap->real_size += segment_size;
    1871           58007 :                 if (heap->real_size > heap->real_peak) {
    1872           52941 :                         heap->real_peak = heap->real_size;
    1873                 :                 }
    1874                 : 
    1875           58007 :                 segment->size = segment_size;
    1876           58007 :                 segment->next_segment = heap->segments_list;
    1877           58007 :                 heap->segments_list = segment;
    1878                 : 
    1879           58007 :                 best_fit = (zend_mm_free_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    1880           58007 :                 ZEND_MM_MARK_FIRST_BLOCK(best_fit);
    1881                 : 
    1882           58007 :                 block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
    1883                 : 
    1884           58007 :                 ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(best_fit, block_size));
    1885                 : 
    1886                 :         } else {
    1887        23661733 : zend_mm_finished_searching_for_block:
    1888                 :                 /* remove from free list */
    1889        23661733 :                 HANDLE_BLOCK_INTERRUPTIONS();
    1890                 :                 ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_FREED);
    1891                 :                 ZEND_MM_CHECK_COOKIE(best_fit);
    1892        23661733 :                 ZEND_MM_CHECK_BLOCK_LINKAGE(best_fit);
    1893        23661733 :                 zend_mm_remove_from_free_list(heap, best_fit);
    1894                 : 
    1895        23661733 :                 block_size = ZEND_MM_FREE_BLOCK_SIZE(best_fit);
    1896                 :         }
    1897                 : 
    1898        23719740 :         remaining_size = block_size - true_size;
    1899                 : 
    1900        23719740 :         if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
    1901        15989172 :                 true_size = block_size;
    1902        15989172 :                 ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
    1903                 :         } else {
    1904                 :                 zend_mm_free_block *new_free_block;
    1905                 : 
    1906                 :                 /* prepare new free block */
    1907         7730568 :                 ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
    1908         7730568 :                 new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(best_fit, true_size);
    1909         7730568 :                 ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
    1910                 : 
    1911                 :                 /* add the new free block to the free list */
    1912         7730568 :                 if (EXPECTED(!keep_rest)) {
    1913         7730563 :                         zend_mm_add_to_free_list(heap, new_free_block);
    1914                 :                 } else {
    1915               5 :                         zend_mm_add_to_rest_list(heap, new_free_block);
    1916                 :                 }
    1917                 :         }
    1918                 : 
    1919                 :         ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 1);
    1920                 : 
    1921        23719740 :         heap->size += true_size;
    1922        23719740 :         if (heap->peak < heap->size) {
    1923          102595 :                 heap->peak = heap->size;
    1924                 :         }
    1925                 : 
    1926        23719740 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1927                 : 
    1928        23719740 :         return ZEND_MM_DATA_OF(best_fit);
    1929                 : }
    1930                 : 
    1931                 : 
    1932                 : static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    1933        61620678 : {
    1934                 :         zend_mm_block *mm_block;
    1935                 :         zend_mm_block *next_block;
    1936                 :         size_t size;
    1937                 : 
    1938        61620678 :         if (!ZEND_MM_VALID_PTR(p)) {
    1939               0 :                 return;
    1940                 :         }
    1941                 : 
    1942        61620678 :         mm_block = ZEND_MM_HEADER_OF(p);
    1943        61620678 :         size = ZEND_MM_BLOCK_SIZE(mm_block);
    1944                 :         ZEND_MM_CHECK_PROTECTION(mm_block);
    1945                 : 
    1946                 : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
    1947                 :         memset(ZEND_MM_DATA_OF(mm_block), 0x5a, mm_block->debug.size);
    1948                 : #endif
    1949                 : 
    1950                 : #if ZEND_MM_CACHE
    1951        61620678 :         if (EXPECTED(ZEND_MM_SMALL_SIZE(size)) && EXPECTED(heap->cached < ZEND_MM_CACHE_SIZE)) {
    1952        37960836 :                 size_t index = ZEND_MM_BUCKET_INDEX(size);
    1953        37960836 :                 zend_mm_free_block **cache = &heap->cache[index];
    1954                 : 
    1955        37960836 :                 ((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
    1956        37960836 :                 *cache = (zend_mm_free_block*)mm_block;
    1957        37960836 :                 heap->cached += size;
    1958                 :                 ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
    1959                 : #if ZEND_MM_CACHE_STAT
    1960                 :                 if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
    1961                 :                         heap->cache_stat[index].max_count = heap->cache_stat[index].count;
    1962                 :                 }
    1963                 : #endif
    1964        37960836 :                 return;
    1965                 :         }
    1966                 : #endif
    1967                 : 
    1968        23659842 :         HANDLE_BLOCK_INTERRUPTIONS();
    1969                 : 
    1970        23659842 :         heap->size -= size;
    1971                 : 
    1972        23659842 :         next_block = ZEND_MM_BLOCK_AT(mm_block, size);
    1973        23659842 :         if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
    1974         3815372 :                 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
    1975         3815372 :                 size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
    1976                 :         }
    1977        23659842 :         if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) {
    1978         3830253 :                 mm_block = ZEND_MM_PREV_BLOCK(mm_block);
    1979         3830253 :                 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block);
    1980         3830253 :                 size += ZEND_MM_FREE_BLOCK_SIZE(mm_block);
    1981                 :         }
    1982        23664911 :         if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
    1983                 :             ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(mm_block, size))) {
    1984            5069 :                 zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE));
    1985                 :         } else {
    1986        23654773 :                 ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size);
    1987        23654773 :                 zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block);
    1988                 :         }
    1989        23659842 :         HANDLE_UNBLOCK_INTERRUPTIONS();
    1990                 : }
    1991                 : 
    1992                 : static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    1993        11261348 : {
    1994        11261348 :         zend_mm_block *mm_block = ZEND_MM_HEADER_OF(p);
    1995                 :         zend_mm_block *next_block;
    1996                 :         size_t true_size;
    1997                 :         size_t orig_size;
    1998                 :         void *ptr;
    1999                 : 
    2000        11261348 :         if (UNEXPECTED(!p) || !ZEND_MM_VALID_PTR(p)) {
    2001         6030896 :                 return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2002                 :         }
    2003         5230452 :         mm_block = ZEND_MM_HEADER_OF(p);
    2004         5230452 :         true_size = ZEND_MM_TRUE_SIZE(size);
    2005         5230452 :         orig_size = ZEND_MM_BLOCK_SIZE(mm_block);
    2006                 :         ZEND_MM_CHECK_PROTECTION(mm_block);
    2007                 : 
    2008         5230452 :         if (UNEXPECTED(true_size < size)) {
    2009               0 :                 goto out_of_memory;
    2010                 :         }
    2011                 : 
    2012         5230452 :         if (true_size <= orig_size) {
    2013         1728980 :                 size_t remaining_size = orig_size - true_size;
    2014                 : 
    2015         1728980 :                 if (remaining_size >= ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
    2016                 :                         zend_mm_free_block *new_free_block;
    2017                 : 
    2018           42542 :                         HANDLE_BLOCK_INTERRUPTIONS();
    2019           42542 :                         next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
    2020           42542 :                         if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
    2021           12289 :                                 remaining_size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
    2022           12289 :                                 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
    2023                 :                         }
    2024                 : 
    2025                 :                         /* prepare new free block */
    2026           42542 :                         ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2027           42542 :                         new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
    2028                 : 
    2029           42542 :                         ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
    2030                 : 
    2031                 :                         /* add the new free block to the free list */
    2032           42542 :                         zend_mm_add_to_free_list(heap, new_free_block);
    2033           42542 :                         heap->size += (true_size - orig_size);
    2034           42542 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    2035                 :                 }
    2036                 :                 ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
    2037         1728980 :                 return p;
    2038                 :         }
    2039                 : 
    2040                 : #if ZEND_MM_CACHE
    2041         3501472 :         if (ZEND_MM_SMALL_SIZE(true_size)) {
    2042         1613284 :                 size_t index = ZEND_MM_BUCKET_INDEX(true_size);
    2043                 :                 
    2044         1613284 :                 if (heap->cache[index] != NULL) {
    2045                 :                         zend_mm_free_block *best_fit;
    2046                 :                         zend_mm_free_block **cache;
    2047                 : 
    2048                 : #if ZEND_MM_CACHE_STAT
    2049                 :                         heap->cache_stat[index].count--;
    2050                 :                         heap->cache_stat[index].hit++;
    2051                 : #endif
    2052         1307417 :                         best_fit = heap->cache[index];
    2053         1307417 :                         heap->cache[index] = best_fit->prev_free_block;
    2054                 :                         ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
    2055                 :                         ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
    2056                 :         
    2057         1307417 :                         ptr = ZEND_MM_DATA_OF(best_fit);
    2058                 : 
    2059                 : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
    2060                 :                         memcpy(ptr, p, mm_block->debug.size);
    2061                 : #else
    2062         1307417 :                         memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
    2063                 : #endif
    2064                 : 
    2065         1307417 :                         heap->cached -= true_size - orig_size;
    2066                 : 
    2067         1307417 :                         index = ZEND_MM_BUCKET_INDEX(orig_size);
    2068         1307417 :                         cache = &heap->cache[index];
    2069                 : 
    2070         1307417 :                         ((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
    2071         1307417 :                         *cache = (zend_mm_free_block*)mm_block;
    2072                 :                         ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
    2073                 : #if ZEND_MM_CACHE_STAT
    2074                 :                         if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
    2075                 :                                 heap->cache_stat[index].max_count = heap->cache_stat[index].count;
    2076                 :                         }
    2077                 : #endif
    2078                 : 
    2079         1307417 :                         return ptr;
    2080                 :                 }
    2081                 :         }
    2082                 : #endif
    2083                 : 
    2084         2194055 :         next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
    2085                 : 
    2086         2194055 :         if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
    2087                 :                 ZEND_MM_CHECK_COOKIE(next_block);
    2088         1657732 :                 ZEND_MM_CHECK_BLOCK_LINKAGE(next_block);
    2089         1657732 :                 if (orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block) >= true_size) {
    2090         1562629 :                         size_t block_size = orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block);
    2091         1562629 :                         size_t remaining_size = block_size - true_size;
    2092                 : 
    2093         1562629 :                         HANDLE_BLOCK_INTERRUPTIONS();
    2094         1562629 :                         zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
    2095                 : 
    2096         1562629 :                         if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
    2097           51236 :                                 true_size = block_size;
    2098           51236 :                                 ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2099                 :                         } else {
    2100                 :                                 zend_mm_free_block *new_free_block;
    2101                 : 
    2102                 :                                 /* prepare new free block */
    2103         1511393 :                                 ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2104         1511393 :                                 new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
    2105         1511393 :                                 ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
    2106                 : 
    2107                 :                                 /* add the new free block to the free list */
    2108         1551343 :                                 if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
    2109                 :                                     ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(new_free_block, remaining_size))) {
    2110           39950 :                                         zend_mm_add_to_rest_list(heap, new_free_block);
    2111                 :                                 } else {
    2112         1471443 :                                         zend_mm_add_to_free_list(heap, new_free_block);
    2113                 :                                 }
    2114                 :                         }
    2115                 :                         ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
    2116         1562629 :                         heap->size = heap->size + true_size - orig_size;
    2117         1562629 :                         if (heap->peak < heap->size) {
    2118            9077 :                                 heap->peak = heap->size;
    2119                 :                         }
    2120         1562629 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    2121         1562629 :                         return p;
    2122           95103 :                 } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
    2123                 :                                    ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(next_block, ZEND_MM_FREE_BLOCK_SIZE(next_block)))) {
    2124               1 :                         HANDLE_BLOCK_INTERRUPTIONS();
    2125               1 :                         zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
    2126               1 :                         goto realloc_segment;
    2127                 :                 }
    2128          536323 :         } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && ZEND_MM_IS_GUARD_BLOCK(next_block)) {
    2129                 :                 zend_mm_segment *segment;
    2130                 :                 zend_mm_segment *segment_copy;
    2131                 :                 size_t segment_size;
    2132                 :                 size_t block_size;
    2133                 :                 size_t remaining_size;
    2134                 : 
    2135               0 :                 HANDLE_BLOCK_INTERRUPTIONS();
    2136               1 : realloc_segment:
    2137                 :                 /* segment size, size of block and size of guard block */
    2138               1 :                 if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
    2139               1 :                         segment_size = true_size+ZEND_MM_ALIGNED_SEGMENT_SIZE+ZEND_MM_ALIGNED_HEADER_SIZE;
    2140               1 :                         segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
    2141                 :                 } else {
    2142               0 :                         segment_size = heap->block_size;
    2143                 :                 }
    2144                 : 
    2145               1 :                 segment_copy = (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE);
    2146               1 :                 if (segment_size < true_size ||
    2147                 :                     heap->real_size + segment_size - segment_copy->size > heap->limit) {
    2148               0 :                         if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
    2149               0 :                                 zend_mm_add_to_free_list(heap, (zend_mm_free_block *) next_block);
    2150                 :                         }
    2151                 : #if ZEND_MM_CACHE
    2152               0 :                         zend_mm_free_cache(heap);
    2153                 : #endif
    2154               0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    2155                 : #if ZEND_DEBUG
    2156                 :                         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);
    2157                 : #else
    2158               0 :                         zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %ld bytes)", heap->limit, size);
    2159                 : #endif
    2160               0 :                         return NULL;
    2161                 :                 }
    2162                 : 
    2163               1 :                 segment = ZEND_MM_STORAGE_REALLOC(segment_copy, segment_size);
    2164               1 :                 if (!segment) {
    2165                 : #if ZEND_MM_CACHE
    2166               0 :                         zend_mm_free_cache(heap);
    2167                 : #endif
    2168               0 :                         HANDLE_UNBLOCK_INTERRUPTIONS();
    2169               0 : out_of_memory:
    2170                 : #if ZEND_DEBUG
    2171                 :                         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);
    2172                 : #else
    2173               0 :                         zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %ld bytes)", heap->real_size, size);
    2174                 : #endif
    2175               0 :                         return NULL;
    2176                 :                 }
    2177               1 :                 heap->real_size += segment_size - segment->size;
    2178               1 :                 if (heap->real_size > heap->real_peak) {
    2179               1 :                         heap->real_peak = heap->real_size;
    2180                 :                 }
    2181                 : 
    2182               1 :                 segment->size = segment_size;
    2183                 : 
    2184               1 :                 if (segment != segment_copy) {
    2185               1 :                         zend_mm_segment **seg = &heap->segments_list;
    2186               2 :                         while (*seg != segment_copy) {
    2187               0 :                                 seg = &(*seg)->next_segment;
    2188                 :                         }
    2189               1 :                         *seg = segment;
    2190               1 :                         mm_block = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
    2191               1 :                         ZEND_MM_MARK_FIRST_BLOCK(mm_block);
    2192                 :                 }
    2193                 : 
    2194               1 :                 block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
    2195               1 :                 remaining_size = block_size - true_size;
    2196                 : 
    2197                 :                 /* setup guard block */
    2198               1 :                 ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(mm_block, block_size));
    2199                 : 
    2200               1 :                 if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
    2201               0 :                         true_size = block_size;
    2202               0 :                         ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2203                 :                 } else {
    2204                 :                         zend_mm_free_block *new_free_block;
    2205                 : 
    2206                 :                         /* prepare new free block */
    2207               1 :                         ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
    2208               1 :                         new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
    2209               1 :                         ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
    2210                 : 
    2211                 :                         /* add the new free block to the free list */
    2212               1 :                         zend_mm_add_to_rest_list(heap, new_free_block);
    2213                 :                 }
    2214                 : 
    2215                 :                 ZEND_MM_SET_DEBUG_INFO(mm_block, size, 1, 1);
    2216                 : 
    2217               1 :                 heap->size = heap->size + true_size - orig_size;
    2218               1 :                 if (heap->peak < heap->size) {
    2219               1 :                         heap->peak = heap->size;
    2220                 :                 }
    2221                 : 
    2222               1 :                 HANDLE_UNBLOCK_INTERRUPTIONS();
    2223               1 :                 return ZEND_MM_DATA_OF(mm_block);
    2224                 :         }
    2225                 : 
    2226          631425 :         ptr = _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2227                 : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
    2228                 :         memcpy(ptr, p, mm_block->debug.size);
    2229                 : #else
    2230          631425 :         memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
    2231                 : #endif
    2232          631425 :         _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2233          631425 :         return ptr;
    2234                 : }
    2235                 : 
    2236                 : ZEND_API void *_zend_mm_alloc(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2237               0 : {
    2238               0 :         return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2239                 : }
    2240                 : 
    2241                 : ZEND_API void _zend_mm_free(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2242               0 : {
    2243               0 :         _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2244               0 : }
    2245                 : 
    2246                 : ZEND_API void *_zend_mm_realloc(zend_mm_heap *heap, void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2247               0 : {
    2248               0 :         return _zend_mm_realloc_int(heap, ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2249                 : }
    2250                 : 
    2251                 : ZEND_API size_t _zend_mm_block_size(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2252               0 : {
    2253                 :         zend_mm_block *mm_block;
    2254                 : 
    2255               0 :         if (!ZEND_MM_VALID_PTR(p)) {
    2256               0 :                 return 0;
    2257                 :         }
    2258               0 :         mm_block = ZEND_MM_HEADER_OF(p);
    2259                 :         ZEND_MM_CHECK_PROTECTION(mm_block);
    2260                 : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
    2261                 :         return mm_block->debug.size;
    2262                 : #else
    2263               0 :         return ZEND_MM_BLOCK_SIZE(mm_block);
    2264                 : #endif
    2265                 : }
    2266                 : 
    2267                 : /**********************/
    2268                 : /* Allocation Manager */
    2269                 : /**********************/
    2270                 : 
    2271                 : typedef struct _zend_alloc_globals {
    2272                 :         zend_mm_heap *mm_heap;
    2273                 : } zend_alloc_globals;
    2274                 : 
    2275                 : #ifdef ZTS
    2276                 : static int alloc_globals_id;
    2277                 : # define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v)
    2278                 : #else
    2279                 : # define AG(v) (alloc_globals.v)
    2280                 : static zend_alloc_globals alloc_globals;
    2281                 : #endif
    2282                 : 
    2283                 : ZEND_API int is_zend_mm(TSRMLS_D)
    2284              26 : {
    2285              26 :         return AG(mm_heap)->use_zend_alloc;
    2286                 : }
    2287                 : 
    2288                 : ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2289       160877183 : {
    2290                 :         TSRMLS_FETCH();
    2291                 : 
    2292       160877183 :         if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
    2293       105918377 :                 return AG(mm_heap)->_malloc(size);
    2294                 :         }
    2295        54958806 :         return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2296                 : }
    2297                 : 
    2298                 : ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2299       170481765 : {
    2300                 :         TSRMLS_FETCH();
    2301                 : 
    2302       170481765 :         if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
    2303       109492512 :                 AG(mm_heap)->_free(ptr);
    2304       109492512 :                 return;
    2305                 :         }
    2306        60989253 :         _zend_mm_free_int(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2307                 : }
    2308                 : 
    2309                 : ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2310        16613596 : {
    2311                 :         TSRMLS_FETCH();
    2312                 : 
    2313        16613596 :         if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
    2314         5352248 :                 return AG(mm_heap)->_realloc(ptr, size);
    2315                 :         }
    2316        11261348 :         return _zend_mm_realloc_int(AG(mm_heap), ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2317                 : }
    2318                 : 
    2319                 : ZEND_API size_t _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2320               0 : {
    2321               0 :         if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
    2322               0 :                 return 0;
    2323                 :         }
    2324               0 :         return _zend_mm_block_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2325                 : }
    2326                 : 
    2327                 : #if defined(__GNUC__) && defined(i386)
    2328                 : 
    2329                 : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
    2330        10945329 : {
    2331        10945329 :         size_t res = nmemb;
    2332        10945329 :         unsigned long overflow = 0;
    2333                 : 
    2334        10945329 :         __asm__ ("mull %3\n\taddl %4,%0\n\tadcl %1,%1"
    2335                 :              : "=&a"(res), "=&d" (overflow)
    2336                 :              : "%0"(res),
    2337                 :                "rm"(size),
    2338                 :                "rm"(offset));
    2339                 :         
    2340        10945329 :         if (UNEXPECTED(overflow)) {
    2341               0 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
    2342                 :                 return 0;
    2343                 :         }
    2344        10945329 :         return res;
    2345                 : }
    2346                 : 
    2347                 : #elif defined(__GNUC__) && defined(__x86_64__)
    2348                 : 
    2349                 : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
    2350                 : {
    2351                 :         size_t res = nmemb;
    2352                 :         unsigned long overflow = 0;
    2353                 : 
    2354                 :         __asm__ ("mulq %3\n\taddq %4,%0\n\tadcq %1,%1"
    2355                 :              : "=&a"(res), "=&d" (overflow)
    2356                 :              : "%0"(res),
    2357                 :                "rm"(size),
    2358                 :                "rm"(offset));
    2359                 : 
    2360                 :         if (UNEXPECTED(overflow)) {
    2361                 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
    2362                 :                 return 0;
    2363                 :         }
    2364                 :         return res;
    2365                 : }
    2366                 : 
    2367                 : #elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64)
    2368                 : 
    2369                 : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
    2370                 : {
    2371                 :         zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset;
    2372                 : 
    2373                 :         if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) {
    2374                 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
    2375                 :                 return 0;
    2376                 :         }
    2377                 :         return (size_t) res;
    2378                 : }
    2379                 : 
    2380                 : #else
    2381                 : 
    2382                 : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
    2383                 : {
    2384                 :         size_t res = nmemb * size + offset;
    2385                 :         double _d  = (double)nmemb * (double)size + (double)offset;
    2386                 :         double _delta = (double)res - _d;
    2387                 : 
    2388                 :         if (UNEXPECTED((_d + _delta ) != _d)) {
    2389                 :                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
    2390                 :                 return 0;
    2391                 :         }
    2392                 :         return res;
    2393                 : }
    2394                 : #endif
    2395                 : 
    2396                 : 
    2397                 : ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2398        10799292 : {
    2399        10799292 :         return emalloc_rel(safe_address(nmemb, size, offset));
    2400                 : }
    2401                 : 
    2402                 : ZEND_API void *_safe_malloc(size_t nmemb, size_t size, size_t offset)
    2403          143786 : {
    2404          143786 :         return pemalloc(safe_address(nmemb, size, offset), 1);
    2405                 : }
    2406                 : 
    2407                 : 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)
    2408            2251 : {
    2409            2251 :         return erealloc_rel(ptr, safe_address(nmemb, size, offset));
    2410                 : }
    2411                 : 
    2412                 : ZEND_API void *_safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset)
    2413               0 : {
    2414               0 :         return perealloc(ptr, safe_address(nmemb, size, offset), 1);
    2415                 : }
    2416                 : 
    2417                 : 
    2418                 : ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2419         8203349 : {
    2420                 :         void *p;
    2421                 : 
    2422         8203349 :         p = _safe_emalloc(nmemb, size, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2423         8203349 :         if (UNEXPECTED(p == NULL)) {
    2424               0 :                 return p;
    2425                 :         }
    2426         8203349 :         memset(p, 0, size * nmemb);
    2427         8203349 :         return p;
    2428                 : }
    2429                 : 
    2430                 : ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2431         2417920 : {
    2432                 :         int length;
    2433                 :         char *p;
    2434                 : 
    2435         2417920 :         length = strlen(s)+1;
    2436         2417920 :         p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2437         2417920 :         if (UNEXPECTED(p == NULL)) {
    2438               0 :                 return p;
    2439                 :         }
    2440         2417920 :         memcpy(p, s, length);
    2441         2417920 :         return p;
    2442                 : }
    2443                 : 
    2444                 : ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2445        21883184 : {
    2446                 :         char *p;
    2447                 : 
    2448        21883184 :         p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2449        21883184 :         if (UNEXPECTED(p == NULL)) {
    2450               0 :                 return p;
    2451                 :         }
    2452        21883184 :         memcpy(p, s, length);
    2453        21883184 :         p[length] = 0;
    2454        21883184 :         return p;
    2455                 : }
    2456                 : 
    2457                 : 
    2458                 : ZEND_API char *zend_strndup(const char *s, uint length)
    2459        46375304 : {
    2460                 :         char *p;
    2461                 : 
    2462        46375304 :         p = (char *) malloc(length+1);
    2463        46375304 :         if (UNEXPECTED(p == NULL)) {
    2464               0 :                 return p;
    2465                 :         }
    2466        46375304 :         if (length) {
    2467        45935478 :                 memcpy(p, s, length);
    2468                 :         }
    2469        46375304 :         p[length] = 0;
    2470        46375304 :         return p;
    2471                 : }
    2472                 : 
    2473                 : 
    2474                 : ZEND_API int zend_set_memory_limit(size_t memory_limit)
    2475           18167 : {
    2476                 :         TSRMLS_FETCH();
    2477                 : 
    2478           18167 :         AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size;
    2479                 : 
    2480           18167 :         return SUCCESS;
    2481                 : }
    2482                 : 
    2483                 : ZEND_API size_t zend_memory_usage(int real_usage TSRMLS_DC)
    2484          472605 : {
    2485          472605 :         if (real_usage) {
    2486            6208 :                 return AG(mm_heap)->real_size;
    2487                 :         } else {
    2488          466397 :                 size_t usage = AG(mm_heap)->size;
    2489                 : #if ZEND_MM_CACHE
    2490          466397 :                 usage -= AG(mm_heap)->cached;
    2491                 : #endif
    2492          466397 :                 return usage;
    2493                 :         }
    2494                 : }
    2495                 : 
    2496                 : ZEND_API size_t zend_memory_peak_usage(int real_usage TSRMLS_DC)
    2497               1 : {
    2498               1 :         if (real_usage) {
    2499               0 :                 return AG(mm_heap)->real_peak;
    2500                 :         } else {
    2501               1 :                 return AG(mm_heap)->peak;
    2502                 :         }
    2503                 : }
    2504                 : 
    2505                 : ZEND_API void shutdown_memory_manager(int silent, int full_shutdown TSRMLS_DC)
    2506           52949 : {
    2507           52949 :         zend_mm_shutdown(AG(mm_heap), full_shutdown, silent TSRMLS_CC);
    2508           52949 : }
    2509                 : 
    2510                 : static void alloc_globals_ctor(zend_alloc_globals *alloc_globals TSRMLS_DC)
    2511           17633 : {
    2512                 :         char *tmp;
    2513           17633 :         alloc_globals->mm_heap = zend_mm_startup();
    2514                 : 
    2515           17633 :         tmp = getenv("USE_ZEND_ALLOC");
    2516           17633 :         if (tmp) {
    2517           17627 :                 alloc_globals->mm_heap->use_zend_alloc = zend_atoi(tmp, 0);
    2518           17627 :                 if (!alloc_globals->mm_heap->use_zend_alloc) {
    2519           17627 :                         alloc_globals->mm_heap->_malloc = malloc;
    2520           17627 :                         alloc_globals->mm_heap->_free = free;
    2521           17627 :                         alloc_globals->mm_heap->_realloc = realloc;
    2522                 :                 }
    2523                 :         }
    2524           17633 : }
    2525                 : 
    2526                 : #ifdef ZTS
    2527                 : static void alloc_globals_dtor(zend_alloc_globals *alloc_globals TSRMLS_DC)
    2528                 : {
    2529                 :         shutdown_memory_manager(1, 1 TSRMLS_CC);
    2530                 : }
    2531                 : #endif
    2532                 : 
    2533                 : ZEND_API void start_memory_manager(TSRMLS_D)
    2534           17633 : {
    2535                 : #ifdef ZTS
    2536                 :         ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor);
    2537                 : #else
    2538           17633 :         alloc_globals_ctor(&alloc_globals);
    2539                 : #endif
    2540           17633 : }
    2541                 : 
    2542                 : ZEND_API zend_mm_heap *zend_mm_set_heap(zend_mm_heap *new_heap TSRMLS_DC)
    2543               0 : {
    2544                 :         zend_mm_heap *old_heap;
    2545                 : 
    2546               0 :         old_heap = AG(mm_heap);
    2547               0 :         AG(mm_heap) = new_heap;
    2548               0 :         return old_heap;
    2549                 : }
    2550                 : 
    2551                 : ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap)
    2552               0 : {
    2553               0 :         return heap->storage;
    2554                 : }
    2555                 : 
    2556                 : ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
    2557                 :                                           void* (*_malloc)(size_t),
    2558                 :                                           void  (*_free)(void*),
    2559                 :                                           void* (*_realloc)(void*, size_t))
    2560               0 : {
    2561               0 :         heap->use_zend_alloc = 0;
    2562               0 :         heap->_malloc = _malloc;
    2563               0 :         heap->_free = _free;
    2564               0 :         heap->_realloc = _realloc;
    2565               0 : }
    2566                 : 
    2567                 : #if ZEND_DEBUG
    2568                 : ZEND_API int _mem_block_check(void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2569                 : {
    2570                 :         TSRMLS_FETCH();
    2571                 : 
    2572                 :         if (!AG(mm_heap)->use_zend_alloc) {
    2573                 :                 return 1;
    2574                 :         }
    2575                 :         return zend_mm_check_ptr(AG(mm_heap), ptr, silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2576                 : }
    2577                 : 
    2578                 : 
    2579                 : ZEND_API void _full_mem_check(int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
    2580                 : {
    2581                 :         int errors;
    2582                 :         TSRMLS_FETCH();
    2583                 : 
    2584                 :         if (!AG(mm_heap)->use_zend_alloc) {
    2585                 :                 return;
    2586                 :         }
    2587                 : 
    2588                 :         zend_debug_alloc_output("------------------------------------------------\n");
    2589                 :         zend_debug_alloc_output("Full Memory Check at %s:%d\n" ZEND_FILE_LINE_RELAY_CC);
    2590                 : 
    2591                 :         errors = zend_mm_check_heap(AG(mm_heap), silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
    2592                 : 
    2593                 :         zend_debug_alloc_output("End of full memory check %s:%d (%d errors)\n" ZEND_FILE_LINE_RELAY_CC, errors);
    2594                 :         zend_debug_alloc_output("------------------------------------------------\n");
    2595                 : }
    2596                 : #endif
    2597                 : 
    2598                 : /*
    2599                 :  * Local variables:
    2600                 :  * tab-width: 4
    2601                 :  * c-basic-offset: 4
    2602                 :  * indent-tabs-mode: t
    2603                 :  * End:
    2604                 :  */

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:26:55 +0000 (3 days ago)

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