root/Zend/zend_alloc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zend_debug_alloc_output
  2. zend_mm_panic
  3. zend_mm_mem_dummy_init
  4. zend_mm_mem_dummy_dtor
  5. zend_mm_mem_dummy_compact
  6. zend_mm_mem_mmap_realloc
  7. zend_mm_mem_mmap_free
  8. zend_mm_mem_mmap_anon_alloc
  9. zend_mm_mem_mmap_zero_init
  10. zend_mm_mem_mmap_zero_dtor
  11. zend_mm_mem_mmap_zero_alloc
  12. zend_mm_mem_win32_init
  13. zend_mm_mem_win32_dtor
  14. zend_mm_mem_win32_compact
  15. zend_mm_mem_win32_alloc
  16. zend_mm_mem_win32_free
  17. zend_mm_mem_win32_realloc
  18. zend_mm_mem_malloc_alloc
  19. zend_mm_mem_malloc_realloc
  20. zend_mm_mem_malloc_free
  21. _zend_mm_alloc_int
  22. zend_mm_low_bit
  23. zend_mm_add_to_free_list
  24. zend_mm_remove_from_free_list
  25. zend_mm_add_to_rest_list
  26. zend_mm_init
  27. zend_mm_del_segment
  28. zend_mm_free_cache
  29. zend_mm_random
  30. zend_mm_startup_ex
  31. zend_mm_startup
  32. zend_mm_find_leaks
  33. zend_mm_check_leaks
  34. zend_mm_check_ptr
  35. zend_mm_check_heap
  36. zend_mm_shutdown
  37. zend_mm_safe_error
  38. zend_mm_search_large_block
  39. _zend_mm_alloc_int
  40. _zend_mm_free_int
  41. _zend_mm_realloc_int
  42. _zend_mm_alloc
  43. _zend_mm_free
  44. _zend_mm_realloc
  45. _zend_mm_block_size
  46. is_zend_mm
  47. _emalloc
  48. _efree
  49. _erealloc
  50. _zend_mem_block_size
  51. safe_address
  52. safe_address
  53. safe_address
  54. safe_address
  55. safe_address
  56. safe_address
  57. _safe_emalloc
  58. _safe_malloc
  59. _safe_erealloc
  60. _safe_realloc
  61. _ecalloc
  62. _estrdup
  63. _estrndup
  64. zend_strndup
  65. zend_set_memory_limit
  66. zend_memory_usage
  67. zend_memory_peak_usage
  68. shutdown_memory_manager
  69. alloc_globals_ctor
  70. alloc_globals_dtor
  71. start_memory_manager
  72. zend_mm_set_heap
  73. zend_mm_get_storage
  74. zend_mm_set_custom_handlers
  75. _mem_block_check
  76. _full_mem_check

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

/* [<][>][^][v][top][bottom][index][help] */