1/* 2 +----------------------------------------------------------------------+ 3 | Zend Engine | 4 +----------------------------------------------------------------------+ 5 | Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) | 6 +----------------------------------------------------------------------+ 7 | This source file is subject to version 2.00 of the Zend license, | 8 | that is bundled with this package in the file LICENSE, and is | 9 | available through the world-wide-web at the following url: | 10 | http://www.zend.com/license/2_00.txt. | 11 | If you did not receive a copy of the Zend license and are unable to | 12 | obtain it through the world-wide-web, please send a note to | 13 | license@zend.com so we can mail you a copy immediately. | 14 +----------------------------------------------------------------------+ 15 | Authors: Andi Gutmans <andi@zend.com> | 16 | Zeev Suraski <zeev@zend.com> | 17 | Dmitry Stogov <dmitry@zend.com> | 18 +----------------------------------------------------------------------+ 19*/ 20 21/* $Id$ */ 22 23#include "zend.h" 24#include "zend_alloc.h" 25#include "zend_globals.h" 26#include "zend_operators.h" 27 28#ifdef HAVE_SIGNAL_H 29# include <signal.h> 30#endif 31#ifdef HAVE_UNISTD_H 32# include <unistd.h> 33#endif 34 35#ifdef ZEND_WIN32 36# include <wincrypt.h> 37# include <process.h> 38#endif 39 40#ifndef ZEND_MM_HEAP_PROTECTION 41# define ZEND_MM_HEAP_PROTECTION ZEND_DEBUG 42#endif 43 44#ifndef ZEND_MM_SAFE_UNLINKING 45# define ZEND_MM_SAFE_UNLINKING 1 46#endif 47 48#ifndef ZEND_MM_COOKIES 49# define ZEND_MM_COOKIES ZEND_DEBUG 50#endif 51 52#ifdef _WIN64 53# define PTR_FMT "0x%0.16I64x" 54/* 55#elif sizeof(long) == 8 56# define PTR_FMT "0x%0.16lx" 57*/ 58#else 59# define PTR_FMT "0x%0.8lx" 60#endif 61 62#if ZEND_DEBUG 63void 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) 81static void zend_mm_panic(const char *message) __attribute__ ((noreturn)); 82#endif 83 84static 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 137static zend_mm_storage* zend_mm_mem_dummy_init(void *params) 138{ 139 return malloc(sizeof(zend_mm_storage)); 140} 141 142static void zend_mm_mem_dummy_dtor(zend_mm_storage *storage) 143{ 144 free(storage); 145} 146 147static 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 153static 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 176static 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 185static 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 200static int zend_mm_dev_zero_fd = -1; 201 202static 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 214static void zend_mm_mem_mmap_zero_dtor(zend_mm_storage *storage) 215{ 216 close(zend_mm_dev_zero_fd); 217 free(storage); 218} 219 220static 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 235static 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 252static void zend_mm_mem_win32_dtor(zend_mm_storage *storage) 253{ 254 HeapDestroy((HANDLE)storage->data); 255 free(storage); 256} 257 258static 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 264static 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 269static 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 274static 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 285static 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 290static 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 295static 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 304static 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 */ 336typedef 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 346typedef 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 359typedef struct _zend_mm_debug_info { 360 size_t size; 361 unsigned int start_magic; 362} zend_mm_debug_info; 363 364#endif 365 366typedef 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 379typedef 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 391typedef 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 415struct _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 469static 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 625static unsigned int _mem_block_start_magic = 0; 626static 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 661static 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); 662static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC); 663static 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 665static 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__)) 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 693static 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__)) 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 727static 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 788static 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 821subst_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 861static 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 892static 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 919static 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 932static 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 977static 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 */ 1042ZEND_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 1163ZEND_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 1234static 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 1275static 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 1335static 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 1559static 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 1601ZEND_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 1743static 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 1807static 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 1880static 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 1989out_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 { 2016zend_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 2060static 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 2123static 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 2269realloc_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 2301out_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 2370ZEND_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 2375ZEND_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 2380ZEND_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 2385ZEND_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 2405typedef struct _zend_alloc_globals { 2406 zend_mm_heap *mm_heap; 2407} zend_alloc_globals; 2408 2409#ifdef ZTS 2410static 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) 2414static zend_alloc_globals alloc_globals; 2415#endif 2416 2417ZEND_API int is_zend_mm(TSRMLS_D) 2418{ 2419 return AG(mm_heap)->use_zend_alloc; 2420} 2421 2422ZEND_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 2432ZEND_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 2443ZEND_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 2453ZEND_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 2463static 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 %1,%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 2483static 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 %1,%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 2512static 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 2533static 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,%1" 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 2553static 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 2566static 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 2581ZEND_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 2586ZEND_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 2591ZEND_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 2596ZEND_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 2602ZEND_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 2620ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2621{ 2622 int length; 2623 char *p; 2624#ifdef ZEND_SIGNALS 2625 TSRMLS_FETCH(); 2626#endif 2627 2628 HANDLE_BLOCK_INTERRUPTIONS(); 2629 2630 length = strlen(s)+1; 2631 p = (char *) _emalloc(length 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); 2637 HANDLE_UNBLOCK_INTERRUPTIONS(); 2638 return p; 2639} 2640 2641ZEND_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(length+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 2662ZEND_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(length+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 2685ZEND_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 2694ZEND_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 2707ZEND_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 2716ZEND_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 2721static 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 2738static void alloc_globals_dtor(zend_alloc_globals *alloc_globals TSRMLS_DC) 2739{ 2740 shutdown_memory_manager(1, 1 TSRMLS_CC); 2741} 2742#endif 2743 2744ZEND_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 2753ZEND_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 2762ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap) 2763{ 2764 return heap->storage; 2765} 2766 2767ZEND_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 2779ZEND_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 2790ZEND_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 */ 2816