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; 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); 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)); 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)); 676 return (unsigned int)n; 677#elif defined(_MSC_VER) && defined(_M_IX86) 678 __asm { 679 bsr eax, _size 680 } 681#else 682 unsigned int n = 0; 683 while (_size != 0) { 684 _size = _size >> 1; 685 n++; 686 } 687 return n-1; 688#endif 689} 690 691static inline unsigned int zend_mm_low_bit(size_t _size) 692{ 693#if defined(__GNUC__) && (defined(__native_client__) || defined(i386)) 694 unsigned int n; 695 696 __asm__("bsfl %1,%0\n\t" : "=r" (n) : "rm" (_size)); 697 return n; 698#elif defined(__GNUC__) && defined(__x86_64__) 699 unsigned long n; 700 701 __asm__("bsf %1,%0\n\t" : "=r" (n) : "rm" (_size)); 702 return (unsigned int)n; 703#elif defined(_MSC_VER) && defined(_M_IX86) 704 __asm { 705 bsf eax, _size 706 } 707#else 708 static const int offset[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0}; 709 unsigned int n; 710 unsigned int index = 0; 711 712 n = offset[_size & 15]; 713 while (n == 4) { 714 _size >>= 4; 715 index += n; 716 n = offset[_size & 15]; 717 } 718 719 return index + n; 720#endif 721} 722 723static inline void zend_mm_add_to_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block) 724{ 725 size_t size; 726 size_t index; 727 728 ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED); 729 730 size = ZEND_MM_FREE_BLOCK_SIZE(mm_block); 731 if (EXPECTED(!ZEND_MM_SMALL_SIZE(size))) { 732 zend_mm_free_block **p; 733 734 index = ZEND_MM_LARGE_BUCKET_INDEX(size); 735 p = &heap->large_free_buckets[index]; 736 mm_block->child[0] = mm_block->child[1] = NULL; 737 if (!*p) { 738 *p = mm_block; 739 mm_block->parent = p; 740 mm_block->prev_free_block = mm_block->next_free_block = mm_block; 741 heap->large_free_bitmap |= (ZEND_MM_LONG_CONST(1) << index); 742 } else { 743 size_t m; 744 745 for (m = size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) { 746 zend_mm_free_block *prev = *p; 747 748 if (ZEND_MM_FREE_BLOCK_SIZE(prev) != size) { 749 p = &prev->child[(m >> (ZEND_MM_NUM_BUCKETS-1)) & 1]; 750 if (!*p) { 751 *p = mm_block; 752 mm_block->parent = p; 753 mm_block->prev_free_block = mm_block->next_free_block = mm_block; 754 break; 755 } 756 } else { 757 zend_mm_free_block *next = prev->next_free_block; 758 759 prev->next_free_block = next->prev_free_block = mm_block; 760 mm_block->next_free_block = next; 761 mm_block->prev_free_block = prev; 762 mm_block->parent = NULL; 763 break; 764 } 765 } 766 } 767 } else { 768 zend_mm_free_block *prev, *next; 769 770 index = ZEND_MM_BUCKET_INDEX(size); 771 772 prev = ZEND_MM_SMALL_FREE_BUCKET(heap, index); 773 if (prev->prev_free_block == prev) { 774 heap->free_bitmap |= (ZEND_MM_LONG_CONST(1) << index); 775 } 776 next = prev->next_free_block; 777 778 mm_block->prev_free_block = prev; 779 mm_block->next_free_block = next; 780 prev->next_free_block = next->prev_free_block = mm_block; 781 } 782} 783 784static inline void zend_mm_remove_from_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block) 785{ 786 zend_mm_free_block *prev = mm_block->prev_free_block; 787 zend_mm_free_block *next = mm_block->next_free_block; 788 789 ZEND_MM_CHECK_MAGIC(mm_block, MEM_BLOCK_FREED); 790 791 if (EXPECTED(prev == mm_block)) { 792 zend_mm_free_block **rp, **cp; 793 794#if ZEND_MM_SAFE_UNLINKING 795 if (UNEXPECTED(next != mm_block)) { 796 zend_mm_panic("zend_mm_heap corrupted"); 797 } 798#endif 799 800 rp = &mm_block->child[mm_block->child[1] != NULL]; 801 prev = *rp; 802 if (EXPECTED(prev == NULL)) { 803 size_t index = ZEND_MM_LARGE_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block)); 804 805 ZEND_MM_CHECK_TREE(mm_block); 806 *mm_block->parent = NULL; 807 if (mm_block->parent == &heap->large_free_buckets[index]) { 808 heap->large_free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index); 809 } 810 } else { 811 while (*(cp = &(prev->child[prev->child[1] != NULL])) != NULL) { 812 prev = *cp; 813 rp = cp; 814 } 815 *rp = NULL; 816 817subst_block: 818 ZEND_MM_CHECK_TREE(mm_block); 819 *mm_block->parent = prev; 820 prev->parent = mm_block->parent; 821 if ((prev->child[0] = mm_block->child[0])) { 822 ZEND_MM_CHECK_TREE(prev->child[0]); 823 prev->child[0]->parent = &prev->child[0]; 824 } 825 if ((prev->child[1] = mm_block->child[1])) { 826 ZEND_MM_CHECK_TREE(prev->child[1]); 827 prev->child[1]->parent = &prev->child[1]; 828 } 829 } 830 } else { 831 832#if ZEND_MM_SAFE_UNLINKING 833 if (UNEXPECTED(prev->next_free_block != mm_block) || UNEXPECTED(next->prev_free_block != mm_block)) { 834 zend_mm_panic("zend_mm_heap corrupted"); 835 } 836#endif 837 838 prev->next_free_block = next; 839 next->prev_free_block = prev; 840 841 if (EXPECTED(ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block)))) { 842 if (EXPECTED(prev == next)) { 843 size_t index = ZEND_MM_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block)); 844 845 if (EXPECTED(heap->free_buckets[index*2] == heap->free_buckets[index*2+1])) { 846 heap->free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index); 847 } 848 } 849 } else if (UNEXPECTED(mm_block->parent == ZEND_MM_REST_BLOCK)) { 850 heap->rest_count--; 851 } else if (UNEXPECTED(mm_block->parent != NULL)) { 852 goto subst_block; 853 } 854 } 855} 856 857static inline void zend_mm_add_to_rest_list(zend_mm_heap *heap, zend_mm_free_block *mm_block) 858{ 859 zend_mm_free_block *prev, *next; 860 861 while (heap->rest_count >= ZEND_MM_MAX_REST_BLOCKS) { 862 zend_mm_free_block *p = heap->rest_buckets[1]; 863 864 if (!ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(p))) { 865 heap->rest_count--; 866 } 867 prev = p->prev_free_block; 868 next = p->next_free_block; 869 prev->next_free_block = next; 870 next->prev_free_block = prev; 871 zend_mm_add_to_free_list(heap, p); 872 } 873 874 if (!ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block))) { 875 mm_block->parent = ZEND_MM_REST_BLOCK; 876 heap->rest_count++; 877 } 878 879 ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED); 880 881 prev = heap->rest_buckets[0]; 882 next = prev->next_free_block; 883 mm_block->prev_free_block = prev; 884 mm_block->next_free_block = next; 885 prev->next_free_block = next->prev_free_block = mm_block; 886} 887 888static inline void zend_mm_init(zend_mm_heap *heap) 889{ 890 zend_mm_free_block* p; 891 int i; 892 893 heap->free_bitmap = 0; 894 heap->large_free_bitmap = 0; 895#if ZEND_MM_CACHE 896 heap->cached = 0; 897 memset(heap->cache, 0, sizeof(heap->cache)); 898#endif 899#if ZEND_MM_CACHE_STAT 900 for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) { 901 heap->cache_stat[i].count = 0; 902 } 903#endif 904 p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0); 905 for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) { 906 p->next_free_block = p; 907 p->prev_free_block = p; 908 p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2); 909 heap->large_free_buckets[i] = NULL; 910 } 911 heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap); 912 heap->rest_count = 0; 913} 914 915static void zend_mm_del_segment(zend_mm_heap *heap, zend_mm_segment *segment) 916{ 917 zend_mm_segment **p = &heap->segments_list; 918 919 while (*p != segment) { 920 p = &(*p)->next_segment; 921 } 922 *p = segment->next_segment; 923 heap->real_size -= segment->size; 924 ZEND_MM_STORAGE_FREE(segment); 925} 926 927#if ZEND_MM_CACHE 928static void zend_mm_free_cache(zend_mm_heap *heap) 929{ 930 int i; 931 932 for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) { 933 if (heap->cache[i]) { 934 zend_mm_free_block *mm_block = heap->cache[i]; 935 936 while (mm_block) { 937 size_t size = ZEND_MM_BLOCK_SIZE(mm_block); 938 zend_mm_free_block *q = mm_block->prev_free_block; 939 zend_mm_block *next_block = ZEND_MM_NEXT_BLOCK(mm_block); 940 941 heap->cached -= size; 942 943 if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) { 944 mm_block = (zend_mm_free_block*)ZEND_MM_PREV_BLOCK(mm_block); 945 size += ZEND_MM_FREE_BLOCK_SIZE(mm_block); 946 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block); 947 } 948 if (ZEND_MM_IS_FREE_BLOCK(next_block)) { 949 size += ZEND_MM_FREE_BLOCK_SIZE(next_block); 950 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block); 951 } 952 ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size); 953 954 if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && 955 ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_NEXT_BLOCK(mm_block))) { 956 zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE)); 957 } else { 958 zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block); 959 } 960 961 mm_block = q; 962 } 963 heap->cache[i] = NULL; 964#if ZEND_MM_CACHE_STAT 965 heap->cache_stat[i].count = 0; 966#endif 967 } 968 } 969} 970#endif 971 972#if ZEND_MM_HEAP_PROTECTION || ZEND_MM_COOKIES 973static void zend_mm_random(unsigned char *buf, size_t size) /* {{{ */ 974{ 975 size_t i = 0; 976 unsigned char t; 977 978#ifdef ZEND_WIN32 979 HCRYPTPROV hCryptProv; 980 int has_context = 0; 981 982 if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) { 983 /* Could mean that the key container does not exist, let try 984 again by asking for a new one */ 985 if (GetLastError() == NTE_BAD_KEYSET) { 986 if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { 987 has_context = 1; 988 } 989 } 990 } else { 991 has_context = 1; 992 } 993 if (has_context) { 994 do { 995 BOOL ret = CryptGenRandom(hCryptProv, size, buf); 996 CryptReleaseContext(hCryptProv, 0); 997 if (ret) { 998 while (i < size && buf[i] != 0) { 999 i++; 1000 } 1001 if (i == size) { 1002 return; 1003 } 1004 } 1005 } while (0); 1006 } 1007#elif defined(HAVE_DEV_URANDOM) 1008 int fd = open("/dev/urandom", 0); 1009 1010 if (fd >= 0) { 1011 if (read(fd, buf, size) == size) { 1012 while (i < size && buf[i] != 0) { 1013 i++; 1014 } 1015 if (i == size) { 1016 close(fd); 1017 return; 1018 } 1019 } 1020 close(fd); 1021 } 1022#endif 1023 t = (unsigned char)getpid(); 1024 while (i < size) { 1025 do { 1026 buf[i] = ((unsigned char)rand()) ^ t; 1027 } while (buf[i] == 0); 1028 t = buf[i++] << 1; 1029 } 1030} 1031/* }}} */ 1032#endif 1033 1034/* Notes: 1035 * - This function may alter the block_sizes values to match platform alignment 1036 * - This function does *not* perform sanity checks on the arguments 1037 */ 1038ZEND_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) 1039{ 1040 zend_mm_storage *storage; 1041 zend_mm_heap *heap; 1042 1043#if 0 1044 int i; 1045 1046 printf("ZEND_MM_ALIGNMENT=%d\n", ZEND_MM_ALIGNMENT); 1047 printf("ZEND_MM_ALIGNMENT_LOG2=%d\n", ZEND_MM_ALIGNMENT_LOG2); 1048 printf("ZEND_MM_MIN_SIZE=%d\n", ZEND_MM_MIN_SIZE); 1049 printf("ZEND_MM_MAX_SMALL_SIZE=%d\n", ZEND_MM_MAX_SMALL_SIZE); 1050 printf("ZEND_MM_ALIGNED_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_HEADER_SIZE); 1051 printf("ZEND_MM_ALIGNED_FREE_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_FREE_HEADER_SIZE); 1052 printf("ZEND_MM_MIN_ALLOC_BLOCK_SIZE=%d\n", ZEND_MM_MIN_ALLOC_BLOCK_SIZE); 1053 printf("ZEND_MM_ALIGNED_MIN_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_MIN_HEADER_SIZE); 1054 printf("ZEND_MM_ALIGNED_SEGMENT_SIZE=%d\n", ZEND_MM_ALIGNED_SEGMENT_SIZE); 1055 for (i = 0; i < ZEND_MM_MAX_SMALL_SIZE; i++) { 1056 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))); 1057 } 1058 exit(0); 1059#endif 1060 1061#if ZEND_MM_HEAP_PROTECTION 1062 if (_mem_block_start_magic == 0) { 1063 zend_mm_random((unsigned char*)&_mem_block_start_magic, sizeof(_mem_block_start_magic)); 1064 } 1065 if (_mem_block_end_magic == 0) { 1066 zend_mm_random((unsigned char*)&_mem_block_end_magic, sizeof(_mem_block_end_magic)); 1067 } 1068#endif 1069#if ZEND_MM_COOKIES 1070 if (_zend_mm_cookie == 0) { 1071 zend_mm_random((unsigned char*)&_zend_mm_cookie, sizeof(_zend_mm_cookie)); 1072 } 1073#endif 1074 1075 if (zend_mm_low_bit(block_size) != zend_mm_high_bit(block_size)) { 1076 fprintf(stderr, "'block_size' must be a power of two\n"); 1077/* See http://support.microsoft.com/kb/190351 */ 1078#ifdef PHP_WIN32 1079 fflush(stderr); 1080#endif 1081 exit(255); 1082 } 1083 storage = handlers->init(params); 1084 if (!storage) { 1085 fprintf(stderr, "Cannot initialize zend_mm storage [%s]\n", handlers->name); 1086/* See http://support.microsoft.com/kb/190351 */ 1087#ifdef PHP_WIN32 1088 fflush(stderr); 1089#endif 1090 exit(255); 1091 } 1092 storage->handlers = handlers; 1093 1094 heap = malloc(sizeof(struct _zend_mm_heap)); 1095 if (heap == NULL) { 1096 fprintf(stderr, "Cannot allocate heap for zend_mm storage [%s]\n", handlers->name); 1097#ifdef PHP_WIN32 1098 fflush(stderr); 1099#endif 1100 exit(255); 1101 } 1102 heap->storage = storage; 1103 heap->block_size = block_size; 1104 heap->compact_size = 0; 1105 heap->segments_list = NULL; 1106 zend_mm_init(heap); 1107# if ZEND_MM_CACHE_STAT 1108 memset(heap->cache_stat, 0, sizeof(heap->cache_stat)); 1109# endif 1110 1111 heap->use_zend_alloc = 1; 1112 heap->real_size = 0; 1113 heap->overflow = 0; 1114 heap->real_peak = 0; 1115 heap->limit = ZEND_MM_LONG_CONST(1)<<(ZEND_MM_NUM_BUCKETS-2); 1116 heap->size = 0; 1117 heap->peak = 0; 1118 heap->internal = internal; 1119 heap->reserve = NULL; 1120 heap->reserve_size = reserve_size; 1121 if (reserve_size > 0) { 1122 heap->reserve = _zend_mm_alloc_int(heap, reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); 1123 } 1124 if (internal) { 1125 int i; 1126 zend_mm_free_block *p, *q, *orig; 1127 zend_mm_heap *mm_heap = _zend_mm_alloc_int(heap, sizeof(zend_mm_heap) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); 1128 1129 *mm_heap = *heap; 1130 1131 p = ZEND_MM_SMALL_FREE_BUCKET(mm_heap, 0); 1132 orig = ZEND_MM_SMALL_FREE_BUCKET(heap, 0); 1133 for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) { 1134 q = p; 1135 while (q->prev_free_block != orig) { 1136 q = q->prev_free_block; 1137 } 1138 q->prev_free_block = p; 1139 q = p; 1140 while (q->next_free_block != orig) { 1141 q = q->next_free_block; 1142 } 1143 q->next_free_block = p; 1144 p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2); 1145 orig = (zend_mm_free_block*)((char*)orig + sizeof(zend_mm_free_block*) * 2); 1146 if (mm_heap->large_free_buckets[i]) { 1147 mm_heap->large_free_buckets[i]->parent = &mm_heap->large_free_buckets[i]; 1148 } 1149 } 1150 mm_heap->rest_buckets[0] = mm_heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(mm_heap); 1151 mm_heap->rest_count = 0; 1152 1153 free(heap); 1154 heap = mm_heap; 1155 } 1156 return heap; 1157} 1158 1159ZEND_API zend_mm_heap *zend_mm_startup(void) 1160{ 1161 int i; 1162 size_t seg_size; 1163 char *mem_type = getenv("ZEND_MM_MEM_TYPE"); 1164 char *tmp; 1165 const zend_mm_mem_handlers *handlers; 1166 zend_mm_heap *heap; 1167 1168 if (mem_type == NULL) { 1169 i = 0; 1170 } else { 1171 for (i = 0; mem_handlers[i].name; i++) { 1172 if (strcmp(mem_handlers[i].name, mem_type) == 0) { 1173 break; 1174 } 1175 } 1176 if (!mem_handlers[i].name) { 1177 fprintf(stderr, "Wrong or unsupported zend_mm storage type '%s'\n", mem_type); 1178 fprintf(stderr, " supported types:\n"); 1179/* See http://support.microsoft.com/kb/190351 */ 1180#ifdef PHP_WIN32 1181 fflush(stderr); 1182#endif 1183 for (i = 0; mem_handlers[i].name; i++) { 1184 fprintf(stderr, " '%s'\n", mem_handlers[i].name); 1185 } 1186/* See http://support.microsoft.com/kb/190351 */ 1187#ifdef PHP_WIN32 1188 fflush(stderr); 1189#endif 1190 exit(255); 1191 } 1192 } 1193 handlers = &mem_handlers[i]; 1194 1195 tmp = getenv("ZEND_MM_SEG_SIZE"); 1196 if (tmp) { 1197 seg_size = zend_atoi(tmp, 0); 1198 if (zend_mm_low_bit(seg_size) != zend_mm_high_bit(seg_size)) { 1199 fprintf(stderr, "ZEND_MM_SEG_SIZE must be a power of two\n"); 1200/* See http://support.microsoft.com/kb/190351 */ 1201#ifdef PHP_WIN32 1202 fflush(stderr); 1203#endif 1204 exit(255); 1205 } else if (seg_size < ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE) { 1206 fprintf(stderr, "ZEND_MM_SEG_SIZE is too small\n"); 1207/* See http://support.microsoft.com/kb/190351 */ 1208#ifdef PHP_WIN32 1209 fflush(stderr); 1210#endif 1211 exit(255); 1212 } 1213 } else { 1214 seg_size = ZEND_MM_SEG_SIZE; 1215 } 1216 1217 heap = zend_mm_startup_ex(handlers, seg_size, ZEND_MM_RESERVE_SIZE, 0, NULL); 1218 if (heap) { 1219 tmp = getenv("ZEND_MM_COMPACT"); 1220 if (tmp) { 1221 heap->compact_size = zend_atoi(tmp, 0); 1222 } else { 1223 heap->compact_size = 2 * 1024 * 1024; 1224 } 1225 } 1226 return heap; 1227} 1228 1229#if ZEND_DEBUG 1230static long zend_mm_find_leaks(zend_mm_segment *segment, zend_mm_block *b) 1231{ 1232 long leaks = 0; 1233 zend_mm_block *p, *q; 1234 1235 p = ZEND_MM_NEXT_BLOCK(b); 1236 while (1) { 1237 if (ZEND_MM_IS_GUARD_BLOCK(p)) { 1238 ZEND_MM_CHECK_MAGIC(p, MEM_BLOCK_GUARD); 1239 segment = segment->next_segment; 1240 if (!segment) { 1241 break; 1242 } 1243 p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE); 1244 continue; 1245 } 1246 q = ZEND_MM_NEXT_BLOCK(p); 1247 if (q <= p || 1248 (char*)q > (char*)segment + segment->size || 1249 p->info._size != q->info._prev) { 1250 zend_mm_panic("zend_mm_heap corrupted"); 1251 } 1252 if (!ZEND_MM_IS_FREE_BLOCK(p)) { 1253 if (p->magic == MEM_BLOCK_VALID) { 1254 if (p->debug.filename==b->debug.filename && p->debug.lineno==b->debug.lineno) { 1255 ZEND_MM_SET_MAGIC(p, MEM_BLOCK_LEAK); 1256 leaks++; 1257 } 1258#if ZEND_MM_CACHE 1259 } else if (p->magic == MEM_BLOCK_CACHED) { 1260 /* skip it */ 1261#endif 1262 } else if (p->magic != MEM_BLOCK_LEAK) { 1263 zend_mm_panic("zend_mm_heap corrupted"); 1264 } 1265 } 1266 p = q; 1267 } 1268 return leaks; 1269} 1270 1271static void zend_mm_check_leaks(zend_mm_heap *heap TSRMLS_DC) 1272{ 1273 zend_mm_segment *segment = heap->segments_list; 1274 zend_mm_block *p, *q; 1275 zend_uint total = 0; 1276 1277 if (!segment) { 1278 return; 1279 } 1280 p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE); 1281 while (1) { 1282 q = ZEND_MM_NEXT_BLOCK(p); 1283 if (q <= p || 1284 (char*)q > (char*)segment + segment->size || 1285 p->info._size != q->info._prev) { 1286 zend_mm_panic("zend_mm_heap corrupted"); 1287 } 1288 if (!ZEND_MM_IS_FREE_BLOCK(p)) { 1289 if (p->magic == MEM_BLOCK_VALID) { 1290 long repeated; 1291 zend_leak_info leak; 1292 1293 ZEND_MM_SET_MAGIC(p, MEM_BLOCK_LEAK); 1294 1295 leak.addr = ZEND_MM_DATA_OF(p); 1296 leak.size = p->debug.size; 1297 leak.filename = p->debug.filename; 1298 leak.lineno = p->debug.lineno; 1299 leak.orig_filename = p->debug.orig_filename; 1300 leak.orig_lineno = p->debug.orig_lineno; 1301 1302 zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC); 1303 zend_message_dispatcher(ZMSG_MEMORY_LEAK_DETECTED, &leak TSRMLS_CC); 1304 repeated = zend_mm_find_leaks(segment, p); 1305 total += 1 + repeated; 1306 if (repeated) { 1307 zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(zend_uintptr_t)repeated TSRMLS_CC); 1308 } 1309#if ZEND_MM_CACHE 1310 } else if (p->magic == MEM_BLOCK_CACHED) { 1311 /* skip it */ 1312#endif 1313 } else if (p->magic != MEM_BLOCK_LEAK) { 1314 zend_mm_panic("zend_mm_heap corrupted"); 1315 } 1316 } 1317 if (ZEND_MM_IS_GUARD_BLOCK(q)) { 1318 segment = segment->next_segment; 1319 if (!segment) { 1320 break; 1321 } 1322 q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE); 1323 } 1324 p = q; 1325 } 1326 if (total) { 1327 zend_message_dispatcher(ZMSG_MEMORY_LEAKS_GRAND_TOTAL, &total TSRMLS_CC); 1328 } 1329} 1330 1331static int zend_mm_check_ptr(zend_mm_heap *heap, void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 1332{ 1333 zend_mm_block *p; 1334 int no_cache_notice = 0; 1335 int had_problems = 0; 1336 int valid_beginning = 1; 1337 1338 if (silent==2) { 1339 silent = 1; 1340 no_cache_notice = 1; 1341 } else if (silent==3) { 1342 silent = 0; 1343 no_cache_notice = 1; 1344 } 1345 if (!silent) { 1346 TSRMLS_FETCH(); 1347 1348 zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC); 1349 zend_debug_alloc_output("---------------------------------------\n"); 1350 zend_debug_alloc_output("%s(%d) : Block "PTR_FMT" status:\n" ZEND_FILE_LINE_RELAY_CC, ptr); 1351 if (__zend_orig_filename) { 1352 zend_debug_alloc_output("%s(%d) : Actual location (location was relayed)\n" ZEND_FILE_LINE_ORIG_RELAY_CC); 1353 } 1354 if (!ptr) { 1355 zend_debug_alloc_output("NULL\n"); 1356 zend_debug_alloc_output("---------------------------------------\n"); 1357 return 0; 1358 } 1359 } 1360 1361 if (!ptr) { 1362 if (silent) { 1363 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1364 } 1365 } 1366 1367 p = ZEND_MM_HEADER_OF(ptr); 1368 1369#ifdef ZTS 1370 if (ZEND_MM_BAD_THREAD_ID(p)) { 1371 if (!silent) { 1372 zend_debug_alloc_output("Invalid pointer: ((thread_id=0x%0.8X) != (expected=0x%0.8X))\n", (long)p->thread_id, (long)tsrm_thread_id()); 1373 had_problems = 1; 1374 } else { 1375 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1376 } 1377 } 1378#endif 1379 1380 if (p->info._size != ZEND_MM_NEXT_BLOCK(p)->info._prev) { 1381 if (!silent) { 1382 zend_debug_alloc_output("Invalid pointer: ((size="PTR_FMT") != (next.prev="PTR_FMT"))\n", p->info._size, ZEND_MM_NEXT_BLOCK(p)->info._prev); 1383 had_problems = 1; 1384 } else { 1385 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1386 } 1387 } 1388 if (p->info._prev != ZEND_MM_GUARD_BLOCK && 1389 ZEND_MM_PREV_BLOCK(p)->info._size != p->info._prev) { 1390 if (!silent) { 1391 zend_debug_alloc_output("Invalid pointer: ((prev="PTR_FMT") != (prev.size="PTR_FMT"))\n", p->info._prev, ZEND_MM_PREV_BLOCK(p)->info._size); 1392 had_problems = 1; 1393 } else { 1394 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1395 } 1396 } 1397 1398 if (had_problems) { 1399 zend_debug_alloc_output("---------------------------------------\n"); 1400 return 0; 1401 } 1402 1403 if (!silent) { 1404 zend_debug_alloc_output("%10s\t","Beginning: "); 1405 } 1406 1407 if (!ZEND_MM_IS_USED_BLOCK(p)) { 1408 if (!silent) { 1409 if (p->magic != MEM_BLOCK_FREED) { 1410 zend_debug_alloc_output("Freed (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED); 1411 } else { 1412 zend_debug_alloc_output("Freed\n"); 1413 } 1414 had_problems = 1; 1415 } else { 1416 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1417 } 1418 } else if (ZEND_MM_IS_GUARD_BLOCK(p)) { 1419 if (!silent) { 1420 if (p->magic != MEM_BLOCK_FREED) { 1421 zend_debug_alloc_output("Guard (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED); 1422 } else { 1423 zend_debug_alloc_output("Guard\n"); 1424 } 1425 had_problems = 1; 1426 } else { 1427 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1428 } 1429 } else { 1430 switch (p->magic) { 1431 case MEM_BLOCK_VALID: 1432 case MEM_BLOCK_LEAK: 1433 if (!silent) { 1434 zend_debug_alloc_output("OK (allocated on %s:%d, %d bytes)\n", p->debug.filename, p->debug.lineno, (int)p->debug.size); 1435 } 1436 break; /* ok */ 1437 case MEM_BLOCK_CACHED: 1438 if (!no_cache_notice) { 1439 if (!silent) { 1440 zend_debug_alloc_output("Cached\n"); 1441 had_problems = 1; 1442 } else { 1443 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1444 } 1445 } 1446 case MEM_BLOCK_FREED: 1447 if (!silent) { 1448 zend_debug_alloc_output("Freed (invalid)\n"); 1449 had_problems = 1; 1450 } else { 1451 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1452 } 1453 break; 1454 case MEM_BLOCK_GUARD: 1455 if (!silent) { 1456 zend_debug_alloc_output("Guard (invalid)\n"); 1457 had_problems = 1; 1458 } else { 1459 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1460 } 1461 break; 1462 default: 1463 if (!silent) { 1464 zend_debug_alloc_output("Unknown (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_VALID); 1465 had_problems = 1; 1466 valid_beginning = 0; 1467 } else { 1468 return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1469 } 1470 break; 1471 } 1472 } 1473 1474#if ZEND_MM_HEAP_PROTECTION 1475 if (!valid_beginning) { 1476 if (!silent) { 1477 zend_debug_alloc_output("%10s\t", "Start:"); 1478 zend_debug_alloc_output("Unknown\n"); 1479 zend_debug_alloc_output("%10s\t", "End:"); 1480 zend_debug_alloc_output("Unknown\n"); 1481 } 1482 } else { 1483 char *end_magic = ZEND_MM_END_MAGIC_PTR(p); 1484 1485 if (p->debug.start_magic == _mem_block_start_magic) { 1486 if (!silent) { 1487 zend_debug_alloc_output("%10s\t", "Start:"); 1488 zend_debug_alloc_output("OK\n"); 1489 } 1490 } else { 1491 char *overflow_ptr, *magic_ptr=(char *) &_mem_block_start_magic; 1492 int overflows=0; 1493 int i; 1494 1495 if (silent) { 1496 return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1497 } 1498 had_problems = 1; 1499 overflow_ptr = (char *) &p->debug.start_magic; 1500 i = END_MAGIC_SIZE; 1501 while (--i >= 0) { 1502 if (overflow_ptr[i]!=magic_ptr[i]) { 1503 overflows++; 1504 } 1505 } 1506 zend_debug_alloc_output("%10s\t", "Start:"); 1507 zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", p->debug.start_magic, _mem_block_start_magic); 1508 zend_debug_alloc_output("%10s\t",""); 1509 if (overflows >= END_MAGIC_SIZE) { 1510 zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE); 1511 } else { 1512 zend_debug_alloc_output("%d byte(s) overflown\n", overflows); 1513 } 1514 } 1515 if (memcmp(end_magic, &_mem_block_end_magic, END_MAGIC_SIZE)==0) { 1516 if (!silent) { 1517 zend_debug_alloc_output("%10s\t", "End:"); 1518 zend_debug_alloc_output("OK\n"); 1519 } 1520 } else { 1521 char *overflow_ptr, *magic_ptr=(char *) &_mem_block_end_magic; 1522 int overflows=0; 1523 int i; 1524 1525 if (silent) { 1526 return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 1527 } 1528 had_problems = 1; 1529 overflow_ptr = (char *) end_magic; 1530 1531 for (i=0; i < END_MAGIC_SIZE; i++) { 1532 if (overflow_ptr[i]!=magic_ptr[i]) { 1533 overflows++; 1534 } 1535 } 1536 1537 zend_debug_alloc_output("%10s\t", "End:"); 1538 zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", *end_magic, _mem_block_end_magic); 1539 zend_debug_alloc_output("%10s\t",""); 1540 if (overflows >= END_MAGIC_SIZE) { 1541 zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE); 1542 } else { 1543 zend_debug_alloc_output("%d byte(s) overflown\n", overflows); 1544 } 1545 } 1546 } 1547#endif 1548 1549 if (!silent) { 1550 zend_debug_alloc_output("---------------------------------------\n"); 1551 } 1552 return ((!had_problems) ? 1 : 0); 1553} 1554 1555static int zend_mm_check_heap(zend_mm_heap *heap, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 1556{ 1557 zend_mm_segment *segment = heap->segments_list; 1558 zend_mm_block *p, *q; 1559 int errors = 0; 1560 1561 if (!segment) { 1562 return 0; 1563 } 1564 p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE); 1565 while (1) { 1566 q = ZEND_MM_NEXT_BLOCK(p); 1567 if (q <= p || 1568 (char*)q > (char*)segment + segment->size || 1569 p->info._size != q->info._prev) { 1570 zend_mm_panic("zend_mm_heap corrupted"); 1571 } 1572 if (!ZEND_MM_IS_FREE_BLOCK(p)) { 1573 if (p->magic == MEM_BLOCK_VALID || p->magic == MEM_BLOCK_LEAK) { 1574 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)) { 1575 errors++; 1576 } 1577#if ZEND_MM_CACHE 1578 } else if (p->magic == MEM_BLOCK_CACHED) { 1579 /* skip it */ 1580#endif 1581 } else if (p->magic != MEM_BLOCK_LEAK) { 1582 zend_mm_panic("zend_mm_heap corrupted"); 1583 } 1584 } 1585 if (ZEND_MM_IS_GUARD_BLOCK(q)) { 1586 segment = segment->next_segment; 1587 if (!segment) { 1588 return errors; 1589 } 1590 q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE); 1591 } 1592 p = q; 1593 } 1594} 1595#endif 1596 1597ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, int full_shutdown, int silent TSRMLS_DC) 1598{ 1599 zend_mm_storage *storage; 1600 zend_mm_segment *segment; 1601 zend_mm_segment *prev; 1602 int internal; 1603 1604 if (!heap->use_zend_alloc) { 1605 if (full_shutdown) { 1606 free(heap); 1607 } 1608 return; 1609 } 1610 1611 if (heap->reserve) { 1612#if ZEND_DEBUG 1613 if (!silent) { 1614 _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); 1615 } 1616#endif 1617 heap->reserve = NULL; 1618 } 1619 1620#if ZEND_MM_CACHE_STAT 1621 if (full_shutdown) { 1622 FILE *f; 1623 1624 f = fopen("zend_mm.log", "w"); 1625 if (f) { 1626 int i,j; 1627 size_t size, true_size, min_size, max_size; 1628 int hit = 0, miss = 0; 1629 1630 fprintf(f, "\nidx min_size max_size true_size max_len hits misses\n"); 1631 size = 0; 1632 while (1) { 1633 true_size = ZEND_MM_TRUE_SIZE(size); 1634 if (ZEND_MM_SMALL_SIZE(true_size)) { 1635 min_size = size; 1636 i = ZEND_MM_BUCKET_INDEX(true_size); 1637 size++; 1638 while (1) { 1639 true_size = ZEND_MM_TRUE_SIZE(size); 1640 if (ZEND_MM_SMALL_SIZE(true_size)) { 1641 j = ZEND_MM_BUCKET_INDEX(true_size); 1642 if (j > i) { 1643 max_size = size-1; 1644 break; 1645 } 1646 } else { 1647 max_size = size-1; 1648 break; 1649 } 1650 size++; 1651 } 1652 hit += heap->cache_stat[i].hit; 1653 miss += heap->cache_stat[i].miss; 1654 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); 1655 } else { 1656 break; 1657 } 1658 } 1659 fprintf(f, " %8d %8d\n", hit, miss); 1660 fprintf(f, " %8d %8d\n", heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit, heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss); 1661 fclose(f); 1662 } 1663 } 1664#endif 1665 1666#if ZEND_DEBUG 1667 if (!silent) { 1668 zend_mm_check_leaks(heap TSRMLS_CC); 1669 } 1670#endif 1671 1672 internal = heap->internal; 1673 storage = heap->storage; 1674 segment = heap->segments_list; 1675 if (full_shutdown) { 1676 while (segment) { 1677 prev = segment; 1678 segment = segment->next_segment; 1679 ZEND_MM_STORAGE_FREE(prev); 1680 } 1681 heap->segments_list = NULL; 1682 storage->handlers->dtor(storage); 1683 if (!internal) { 1684 free(heap); 1685 } 1686 } else { 1687 if (segment) { 1688#ifndef ZEND_WIN32 1689 if (heap->reserve_size) { 1690 while (segment->next_segment) { 1691 prev = segment; 1692 segment = segment->next_segment; 1693 ZEND_MM_STORAGE_FREE(prev); 1694 } 1695 heap->segments_list = segment; 1696 } else { 1697#endif 1698 do { 1699 prev = segment; 1700 segment = segment->next_segment; 1701 ZEND_MM_STORAGE_FREE(prev); 1702 } while (segment); 1703 heap->segments_list = NULL; 1704#ifndef ZEND_WIN32 1705 } 1706#endif 1707 } 1708 if (heap->compact_size && 1709 heap->real_peak > heap->compact_size) { 1710 storage->handlers->compact(storage); 1711 } 1712 zend_mm_init(heap); 1713 if (heap->segments_list) { 1714 heap->real_size = heap->segments_list->size; 1715 heap->real_peak = heap->segments_list->size; 1716 } else { 1717 heap->real_size = 0; 1718 heap->real_peak = 0; 1719 } 1720 heap->size = 0; 1721 heap->peak = 0; 1722 if (heap->segments_list) { 1723 /* mark segment as a free block */ 1724 zend_mm_free_block *b = (zend_mm_free_block*)((char*)heap->segments_list + ZEND_MM_ALIGNED_SEGMENT_SIZE); 1725 size_t block_size = heap->segments_list->size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE; 1726 1727 ZEND_MM_MARK_FIRST_BLOCK(b); 1728 ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(b, block_size)); 1729 ZEND_MM_BLOCK(b, ZEND_MM_FREE_BLOCK, block_size); 1730 zend_mm_add_to_free_list(heap, b); 1731 } 1732 if (heap->reserve_size) { 1733 heap->reserve = _zend_mm_alloc_int(heap, heap->reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); 1734 } 1735 heap->overflow = 0; 1736 } 1737} 1738 1739static void zend_mm_safe_error(zend_mm_heap *heap, 1740 const char *format, 1741 size_t limit, 1742#if ZEND_DEBUG 1743 const char *filename, 1744 uint lineno, 1745#endif 1746 size_t size) 1747{ 1748 if (heap->reserve) { 1749 _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC); 1750 heap->reserve = NULL; 1751 } 1752 if (heap->overflow == 0) { 1753 const char *error_filename; 1754 uint error_lineno; 1755 TSRMLS_FETCH(); 1756 if (zend_is_compiling(TSRMLS_C)) { 1757 error_filename = zend_get_compiled_filename(TSRMLS_C); 1758 error_lineno = zend_get_compiled_lineno(TSRMLS_C); 1759 } else if (EG(in_execution)) { 1760 error_filename = EG(active_op_array)?EG(active_op_array)->filename:NULL; 1761 error_lineno = EG(opline_ptr)?(*EG(opline_ptr))->lineno:0; 1762 } else { 1763 error_filename = NULL; 1764 error_lineno = 0; 1765 } 1766 if (!error_filename) { 1767 error_filename = "Unknown"; 1768 } 1769 heap->overflow = 1; 1770 zend_try { 1771 zend_error_noreturn(E_ERROR, 1772 format, 1773 limit, 1774#if ZEND_DEBUG 1775 filename, 1776 lineno, 1777#endif 1778 size); 1779 } zend_catch { 1780 if (heap->overflow == 2) { 1781 fprintf(stderr, "\nFatal error: "); 1782 fprintf(stderr, 1783 format, 1784 limit, 1785#if ZEND_DEBUG 1786 filename, 1787 lineno, 1788#endif 1789 size); 1790 fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno); 1791 } 1792/* See http://support.microsoft.com/kb/190351 */ 1793#ifdef PHP_WIN32 1794 fflush(stderr); 1795#endif 1796 } zend_end_try(); 1797 } else { 1798 heap->overflow = 2; 1799 } 1800 zend_bailout(); 1801} 1802 1803static zend_mm_free_block *zend_mm_search_large_block(zend_mm_heap *heap, size_t true_size) 1804{ 1805 zend_mm_free_block *best_fit; 1806 size_t index = ZEND_MM_LARGE_BUCKET_INDEX(true_size); 1807 size_t bitmap = heap->large_free_bitmap >> index; 1808 zend_mm_free_block *p; 1809 1810 if (bitmap == 0) { 1811 return NULL; 1812 } 1813 1814 if (UNEXPECTED((bitmap & 1) != 0)) { 1815 /* Search for best "large" free block */ 1816 zend_mm_free_block *rst = NULL; 1817 size_t m; 1818 size_t best_size = -1; 1819 1820 best_fit = NULL; 1821 p = heap->large_free_buckets[index]; 1822 for (m = true_size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) { 1823 if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) { 1824 return p->next_free_block; 1825 } else if (ZEND_MM_FREE_BLOCK_SIZE(p) >= true_size && 1826 ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) { 1827 best_size = ZEND_MM_FREE_BLOCK_SIZE(p); 1828 best_fit = p; 1829 } 1830 if ((m & (ZEND_MM_LONG_CONST(1) << (ZEND_MM_NUM_BUCKETS-1))) == 0) { 1831 if (p->child[1]) { 1832 rst = p->child[1]; 1833 } 1834 if (p->child[0]) { 1835 p = p->child[0]; 1836 } else { 1837 break; 1838 } 1839 } else if (p->child[1]) { 1840 p = p->child[1]; 1841 } else { 1842 break; 1843 } 1844 } 1845 1846 for (p = rst; p; p = p->child[p->child[0] != NULL]) { 1847 if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) { 1848 return p->next_free_block; 1849 } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size && 1850 ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) { 1851 best_size = ZEND_MM_FREE_BLOCK_SIZE(p); 1852 best_fit = p; 1853 } 1854 } 1855 1856 if (best_fit) { 1857 return best_fit->next_free_block; 1858 } 1859 bitmap = bitmap >> 1; 1860 if (!bitmap) { 1861 return NULL; 1862 } 1863 index++; 1864 } 1865 1866 /* Search for smallest "large" free block */ 1867 best_fit = p = heap->large_free_buckets[index + zend_mm_low_bit(bitmap)]; 1868 while ((p = p->child[p->child[0] != NULL])) { 1869 if (ZEND_MM_FREE_BLOCK_SIZE(p) < ZEND_MM_FREE_BLOCK_SIZE(best_fit)) { 1870 best_fit = p; 1871 } 1872 } 1873 return best_fit->next_free_block; 1874} 1875 1876static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 1877{ 1878 zend_mm_free_block *best_fit; 1879 size_t true_size = ZEND_MM_TRUE_SIZE(size); 1880 size_t block_size; 1881 size_t remaining_size; 1882 size_t segment_size; 1883 zend_mm_segment *segment; 1884 int keep_rest = 0; 1885#ifdef ZEND_SIGNALS 1886 TSRMLS_FETCH(); 1887#endif 1888 1889 HANDLE_BLOCK_INTERRUPTIONS(); 1890 1891 if (EXPECTED(ZEND_MM_SMALL_SIZE(true_size))) { 1892 size_t index = ZEND_MM_BUCKET_INDEX(true_size); 1893 size_t bitmap; 1894 1895 if (UNEXPECTED(true_size < size)) { 1896 goto out_of_memory; 1897 } 1898#if ZEND_MM_CACHE 1899 if (EXPECTED(heap->cache[index] != NULL)) { 1900 /* Get block from cache */ 1901#if ZEND_MM_CACHE_STAT 1902 heap->cache_stat[index].count--; 1903 heap->cache_stat[index].hit++; 1904#endif 1905 best_fit = heap->cache[index]; 1906 heap->cache[index] = best_fit->prev_free_block; 1907 heap->cached -= true_size; 1908 ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED); 1909 ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0); 1910 HANDLE_UNBLOCK_INTERRUPTIONS(); 1911 return ZEND_MM_DATA_OF(best_fit); 1912 } 1913#if ZEND_MM_CACHE_STAT 1914 heap->cache_stat[index].miss++; 1915#endif 1916#endif 1917 1918 bitmap = heap->free_bitmap >> index; 1919 if (bitmap) { 1920 /* Found some "small" free block that can be used */ 1921 index += zend_mm_low_bit(bitmap); 1922 best_fit = heap->free_buckets[index*2]; 1923#if ZEND_MM_CACHE_STAT 1924 heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit++; 1925#endif 1926 goto zend_mm_finished_searching_for_block; 1927 } 1928 } 1929 1930#if ZEND_MM_CACHE_STAT 1931 heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss++; 1932#endif 1933 1934 best_fit = zend_mm_search_large_block(heap, true_size); 1935 1936 if (!best_fit && heap->real_size >= heap->limit - heap->block_size) { 1937 zend_mm_free_block *p = heap->rest_buckets[0]; 1938 size_t best_size = -1; 1939 1940 while (p != ZEND_MM_REST_BUCKET(heap)) { 1941 if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) { 1942 best_fit = p; 1943 goto zend_mm_finished_searching_for_block; 1944 } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size && 1945 ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) { 1946 best_size = ZEND_MM_FREE_BLOCK_SIZE(p); 1947 best_fit = p; 1948 } 1949 p = p->prev_free_block; 1950 } 1951 } 1952 1953 if (!best_fit) { 1954 if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) { 1955 /* Make sure we add a memory block which is big enough, 1956 segment must have header "size" and trailer "guard" block */ 1957 segment_size = true_size + ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE; 1958 segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1); 1959 keep_rest = 1; 1960 } else { 1961 segment_size = heap->block_size; 1962 } 1963 1964 if (segment_size < true_size || 1965 heap->real_size + segment_size > heap->limit) { 1966 /* Memory limit overflow */ 1967#if ZEND_MM_CACHE 1968 zend_mm_free_cache(heap); 1969#endif 1970 HANDLE_UNBLOCK_INTERRUPTIONS(); 1971#if ZEND_DEBUG 1972 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); 1973#else 1974 zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %lu bytes)", heap->limit, size); 1975#endif 1976 } 1977 1978 segment = (zend_mm_segment *) ZEND_MM_STORAGE_ALLOC(segment_size); 1979 1980 if (!segment) { 1981 /* Storage manager cannot allocate memory */ 1982#if ZEND_MM_CACHE 1983 zend_mm_free_cache(heap); 1984#endif 1985out_of_memory: 1986 HANDLE_UNBLOCK_INTERRUPTIONS(); 1987#if ZEND_DEBUG 1988 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); 1989#else 1990 zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %lu bytes)", heap->real_size, size); 1991#endif 1992 return NULL; 1993 } 1994 1995 heap->real_size += segment_size; 1996 if (heap->real_size > heap->real_peak) { 1997 heap->real_peak = heap->real_size; 1998 } 1999 2000 segment->size = segment_size; 2001 segment->next_segment = heap->segments_list; 2002 heap->segments_list = segment; 2003 2004 best_fit = (zend_mm_free_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE); 2005 ZEND_MM_MARK_FIRST_BLOCK(best_fit); 2006 2007 block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE; 2008 2009 ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(best_fit, block_size)); 2010 2011 } else { 2012zend_mm_finished_searching_for_block: 2013 /* remove from free list */ 2014 ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_FREED); 2015 ZEND_MM_CHECK_COOKIE(best_fit); 2016 ZEND_MM_CHECK_BLOCK_LINKAGE(best_fit); 2017 zend_mm_remove_from_free_list(heap, best_fit); 2018 2019 block_size = ZEND_MM_FREE_BLOCK_SIZE(best_fit); 2020 } 2021 2022 remaining_size = block_size - true_size; 2023 2024 if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) { 2025 true_size = block_size; 2026 ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size); 2027 } else { 2028 zend_mm_free_block *new_free_block; 2029 2030 /* prepare new free block */ 2031 ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size); 2032 new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(best_fit, true_size); 2033 ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size); 2034 2035 /* add the new free block to the free list */ 2036 if (EXPECTED(!keep_rest)) { 2037 zend_mm_add_to_free_list(heap, new_free_block); 2038 } else { 2039 zend_mm_add_to_rest_list(heap, new_free_block); 2040 } 2041 } 2042 2043 ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 1); 2044 2045 heap->size += true_size; 2046 if (heap->peak < heap->size) { 2047 heap->peak = heap->size; 2048 } 2049 2050 HANDLE_UNBLOCK_INTERRUPTIONS(); 2051 2052 return ZEND_MM_DATA_OF(best_fit); 2053} 2054 2055 2056static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2057{ 2058 zend_mm_block *mm_block; 2059 zend_mm_block *next_block; 2060 size_t size; 2061#ifdef ZEND_SIGNALS 2062 TSRMLS_FETCH(); 2063#endif 2064 if (!ZEND_MM_VALID_PTR(p)) { 2065 return; 2066 } 2067 2068 HANDLE_BLOCK_INTERRUPTIONS(); 2069 2070 mm_block = ZEND_MM_HEADER_OF(p); 2071 size = ZEND_MM_BLOCK_SIZE(mm_block); 2072 ZEND_MM_CHECK_PROTECTION(mm_block); 2073 2074#if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION 2075 memset(ZEND_MM_DATA_OF(mm_block), 0x5a, mm_block->debug.size); 2076#endif 2077 2078#if ZEND_MM_CACHE 2079 if (EXPECTED(ZEND_MM_SMALL_SIZE(size)) && EXPECTED(heap->cached < ZEND_MM_CACHE_SIZE)) { 2080 size_t index = ZEND_MM_BUCKET_INDEX(size); 2081 zend_mm_free_block **cache = &heap->cache[index]; 2082 2083 ((zend_mm_free_block*)mm_block)->prev_free_block = *cache; 2084 *cache = (zend_mm_free_block*)mm_block; 2085 heap->cached += size; 2086 ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED); 2087#if ZEND_MM_CACHE_STAT 2088 if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) { 2089 heap->cache_stat[index].max_count = heap->cache_stat[index].count; 2090 } 2091#endif 2092 HANDLE_UNBLOCK_INTERRUPTIONS(); 2093 return; 2094 } 2095#endif 2096 2097 heap->size -= size; 2098 2099 next_block = ZEND_MM_BLOCK_AT(mm_block, size); 2100 if (ZEND_MM_IS_FREE_BLOCK(next_block)) { 2101 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block); 2102 size += ZEND_MM_FREE_BLOCK_SIZE(next_block); 2103 } 2104 if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) { 2105 mm_block = ZEND_MM_PREV_BLOCK(mm_block); 2106 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block); 2107 size += ZEND_MM_FREE_BLOCK_SIZE(mm_block); 2108 } 2109 if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && 2110 ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(mm_block, size))) { 2111 zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE)); 2112 } else { 2113 ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size); 2114 zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block); 2115 } 2116 HANDLE_UNBLOCK_INTERRUPTIONS(); 2117} 2118 2119static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2120{ 2121 zend_mm_block *mm_block = ZEND_MM_HEADER_OF(p); 2122 zend_mm_block *next_block; 2123 size_t true_size; 2124 size_t orig_size; 2125 void *ptr; 2126#ifdef ZEND_SIGNALS 2127 TSRMLS_FETCH(); 2128#endif 2129 if (UNEXPECTED(!p) || !ZEND_MM_VALID_PTR(p)) { 2130 return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2131 } 2132 2133 HANDLE_BLOCK_INTERRUPTIONS(); 2134 2135 mm_block = ZEND_MM_HEADER_OF(p); 2136 true_size = ZEND_MM_TRUE_SIZE(size); 2137 orig_size = ZEND_MM_BLOCK_SIZE(mm_block); 2138 ZEND_MM_CHECK_PROTECTION(mm_block); 2139 2140 if (UNEXPECTED(true_size < size)) { 2141 goto out_of_memory; 2142 } 2143 2144 if (true_size <= orig_size) { 2145 size_t remaining_size = orig_size - true_size; 2146 2147 if (remaining_size >= ZEND_MM_ALIGNED_MIN_HEADER_SIZE) { 2148 zend_mm_free_block *new_free_block; 2149 2150 next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size); 2151 if (ZEND_MM_IS_FREE_BLOCK(next_block)) { 2152 remaining_size += ZEND_MM_FREE_BLOCK_SIZE(next_block); 2153 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block); 2154 } 2155 2156 /* prepare new free block */ 2157 ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size); 2158 new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size); 2159 2160 ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size); 2161 2162 /* add the new free block to the free list */ 2163 zend_mm_add_to_free_list(heap, new_free_block); 2164 heap->size += (true_size - orig_size); 2165 } 2166 ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0); 2167 HANDLE_UNBLOCK_INTERRUPTIONS(); 2168 return p; 2169 } 2170 2171#if ZEND_MM_CACHE 2172 if (ZEND_MM_SMALL_SIZE(true_size)) { 2173 size_t index = ZEND_MM_BUCKET_INDEX(true_size); 2174 2175 if (heap->cache[index] != NULL) { 2176 zend_mm_free_block *best_fit; 2177 zend_mm_free_block **cache; 2178 2179#if ZEND_MM_CACHE_STAT 2180 heap->cache_stat[index].count--; 2181 heap->cache_stat[index].hit++; 2182#endif 2183 best_fit = heap->cache[index]; 2184 heap->cache[index] = best_fit->prev_free_block; 2185 ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED); 2186 ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0); 2187 2188 ptr = ZEND_MM_DATA_OF(best_fit); 2189 2190#if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION 2191 memcpy(ptr, p, mm_block->debug.size); 2192#else 2193 memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE); 2194#endif 2195 2196 heap->cached -= true_size - orig_size; 2197 2198 index = ZEND_MM_BUCKET_INDEX(orig_size); 2199 cache = &heap->cache[index]; 2200 2201 ((zend_mm_free_block*)mm_block)->prev_free_block = *cache; 2202 *cache = (zend_mm_free_block*)mm_block; 2203 ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED); 2204#if ZEND_MM_CACHE_STAT 2205 if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) { 2206 heap->cache_stat[index].max_count = heap->cache_stat[index].count; 2207 } 2208#endif 2209 2210 HANDLE_UNBLOCK_INTERRUPTIONS(); 2211 return ptr; 2212 } 2213 } 2214#endif 2215 2216 next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size); 2217 2218 if (ZEND_MM_IS_FREE_BLOCK(next_block)) { 2219 ZEND_MM_CHECK_COOKIE(next_block); 2220 ZEND_MM_CHECK_BLOCK_LINKAGE(next_block); 2221 if (orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block) >= true_size) { 2222 size_t block_size = orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block); 2223 size_t remaining_size = block_size - true_size; 2224 2225 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block); 2226 2227 if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) { 2228 true_size = block_size; 2229 ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size); 2230 } else { 2231 zend_mm_free_block *new_free_block; 2232 2233 /* prepare new free block */ 2234 ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size); 2235 new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size); 2236 ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size); 2237 2238 /* add the new free block to the free list */ 2239 if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && 2240 ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(new_free_block, remaining_size))) { 2241 zend_mm_add_to_rest_list(heap, new_free_block); 2242 } else { 2243 zend_mm_add_to_free_list(heap, new_free_block); 2244 } 2245 } 2246 ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0); 2247 heap->size = heap->size + true_size - orig_size; 2248 if (heap->peak < heap->size) { 2249 heap->peak = heap->size; 2250 } 2251 HANDLE_UNBLOCK_INTERRUPTIONS(); 2252 return p; 2253 } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && 2254 ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(next_block, ZEND_MM_FREE_BLOCK_SIZE(next_block)))) { 2255 zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block); 2256 goto realloc_segment; 2257 } 2258 } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && ZEND_MM_IS_GUARD_BLOCK(next_block)) { 2259 zend_mm_segment *segment; 2260 zend_mm_segment *segment_copy; 2261 size_t segment_size; 2262 size_t block_size; 2263 size_t remaining_size; 2264 2265realloc_segment: 2266 /* segment size, size of block and size of guard block */ 2267 if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) { 2268 segment_size = true_size+ZEND_MM_ALIGNED_SEGMENT_SIZE+ZEND_MM_ALIGNED_HEADER_SIZE; 2269 segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1); 2270 } else { 2271 segment_size = heap->block_size; 2272 } 2273 2274 segment_copy = (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE); 2275 if (segment_size < true_size || 2276 heap->real_size + segment_size - segment_copy->size > heap->limit) { 2277 if (ZEND_MM_IS_FREE_BLOCK(next_block)) { 2278 zend_mm_add_to_free_list(heap, (zend_mm_free_block *) next_block); 2279 } 2280#if ZEND_MM_CACHE 2281 zend_mm_free_cache(heap); 2282#endif 2283 HANDLE_UNBLOCK_INTERRUPTIONS(); 2284#if ZEND_DEBUG 2285 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); 2286#else 2287 zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %ld bytes)", heap->limit, size); 2288#endif 2289 return NULL; 2290 } 2291 2292 segment = ZEND_MM_STORAGE_REALLOC(segment_copy, segment_size); 2293 if (!segment) { 2294#if ZEND_MM_CACHE 2295 zend_mm_free_cache(heap); 2296#endif 2297out_of_memory: 2298 HANDLE_UNBLOCK_INTERRUPTIONS(); 2299#if ZEND_DEBUG 2300 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); 2301#else 2302 zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %ld bytes)", heap->real_size, size); 2303#endif 2304 return NULL; 2305 } 2306 heap->real_size += segment_size - segment->size; 2307 if (heap->real_size > heap->real_peak) { 2308 heap->real_peak = heap->real_size; 2309 } 2310 2311 segment->size = segment_size; 2312 2313 if (segment != segment_copy) { 2314 zend_mm_segment **seg = &heap->segments_list; 2315 while (*seg != segment_copy) { 2316 seg = &(*seg)->next_segment; 2317 } 2318 *seg = segment; 2319 mm_block = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE); 2320 ZEND_MM_MARK_FIRST_BLOCK(mm_block); 2321 } 2322 2323 block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE; 2324 remaining_size = block_size - true_size; 2325 2326 /* setup guard block */ 2327 ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(mm_block, block_size)); 2328 2329 if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) { 2330 true_size = block_size; 2331 ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size); 2332 } else { 2333 zend_mm_free_block *new_free_block; 2334 2335 /* prepare new free block */ 2336 ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size); 2337 new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size); 2338 ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size); 2339 2340 /* add the new free block to the free list */ 2341 zend_mm_add_to_rest_list(heap, new_free_block); 2342 } 2343 2344 ZEND_MM_SET_DEBUG_INFO(mm_block, size, 1, 1); 2345 2346 heap->size = heap->size + true_size - orig_size; 2347 if (heap->peak < heap->size) { 2348 heap->peak = heap->size; 2349 } 2350 2351 HANDLE_UNBLOCK_INTERRUPTIONS(); 2352 return ZEND_MM_DATA_OF(mm_block); 2353 } 2354 2355 ptr = _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2356#if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION 2357 memcpy(ptr, p, mm_block->debug.size); 2358#else 2359 memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE); 2360#endif 2361 _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2362 HANDLE_UNBLOCK_INTERRUPTIONS(); 2363 return ptr; 2364} 2365 2366ZEND_API void *_zend_mm_alloc(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2367{ 2368 return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2369} 2370 2371ZEND_API void _zend_mm_free(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2372{ 2373 _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2374} 2375 2376ZEND_API void *_zend_mm_realloc(zend_mm_heap *heap, void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2377{ 2378 return _zend_mm_realloc_int(heap, ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2379} 2380 2381ZEND_API size_t _zend_mm_block_size(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2382{ 2383 zend_mm_block *mm_block; 2384 2385 if (!ZEND_MM_VALID_PTR(p)) { 2386 return 0; 2387 } 2388 mm_block = ZEND_MM_HEADER_OF(p); 2389 ZEND_MM_CHECK_PROTECTION(mm_block); 2390#if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION 2391 return mm_block->debug.size; 2392#else 2393 return ZEND_MM_BLOCK_SIZE(mm_block); 2394#endif 2395} 2396 2397/**********************/ 2398/* Allocation Manager */ 2399/**********************/ 2400 2401typedef struct _zend_alloc_globals { 2402 zend_mm_heap *mm_heap; 2403} zend_alloc_globals; 2404 2405#ifdef ZTS 2406static int alloc_globals_id; 2407# define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v) 2408#else 2409# define AG(v) (alloc_globals.v) 2410static zend_alloc_globals alloc_globals; 2411#endif 2412 2413ZEND_API int is_zend_mm(TSRMLS_D) 2414{ 2415 return AG(mm_heap)->use_zend_alloc; 2416} 2417 2418ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2419{ 2420 TSRMLS_FETCH(); 2421 2422 if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) { 2423 return AG(mm_heap)->_malloc(size); 2424 } 2425 return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2426} 2427 2428ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2429{ 2430 TSRMLS_FETCH(); 2431 2432 if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) { 2433 AG(mm_heap)->_free(ptr); 2434 return; 2435 } 2436 _zend_mm_free_int(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2437} 2438 2439ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2440{ 2441 TSRMLS_FETCH(); 2442 2443 if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) { 2444 return AG(mm_heap)->_realloc(ptr, size); 2445 } 2446 return _zend_mm_realloc_int(AG(mm_heap), ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2447} 2448 2449ZEND_API size_t _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2450{ 2451 if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) { 2452 return 0; 2453 } 2454 return _zend_mm_block_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2455} 2456 2457#if defined(__GNUC__) && (defined(__native_client__) || defined(i386)) 2458 2459static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) 2460{ 2461 size_t res = nmemb; 2462 unsigned long overflow = 0; 2463 2464 __asm__ ("mull %3\n\taddl %4,%0\n\tadcl %1,%1" 2465 : "=&a"(res), "=&d" (overflow) 2466 : "%0"(res), 2467 "rm"(size), 2468 "rm"(offset)); 2469 2470 if (UNEXPECTED(overflow)) { 2471 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); 2472 return 0; 2473 } 2474 return res; 2475} 2476 2477#elif defined(__GNUC__) && defined(__x86_64__) 2478 2479static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) 2480{ 2481 size_t res = nmemb; 2482 unsigned long overflow = 0; 2483 2484#ifdef __ILP32__ /* x32 */ 2485# define LP_SUFF "l" 2486#else /* amd64 */ 2487# define LP_SUFF "q" 2488#endif 2489 2490 __asm__ ("mul" LP_SUFF " %3\n\t" 2491 "add %4,%0\n\t" 2492 "adc %1,%1" 2493 : "=&a"(res), "=&d" (overflow) 2494 : "%0"(res), 2495 "rm"(size), 2496 "rm"(offset)); 2497 2498#undef LP_SUFF 2499 2500 if (UNEXPECTED(overflow)) { 2501 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); 2502 return 0; 2503 } 2504 return res; 2505} 2506 2507#elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64) 2508 2509static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) 2510{ 2511 zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset; 2512 2513 if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) { 2514 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); 2515 return 0; 2516 } 2517 return (size_t) res; 2518} 2519 2520#else 2521 2522static inline size_t safe_address(size_t nmemb, size_t size, size_t offset) 2523{ 2524 size_t res = nmemb * size + offset; 2525 double _d = (double)nmemb * (double)size + (double)offset; 2526 double _delta = (double)res - _d; 2527 2528 if (UNEXPECTED((_d + _delta ) != _d)) { 2529 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset); 2530 return 0; 2531 } 2532 return res; 2533} 2534#endif 2535 2536 2537ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2538{ 2539 return emalloc_rel(safe_address(nmemb, size, offset)); 2540} 2541 2542ZEND_API void *_safe_malloc(size_t nmemb, size_t size, size_t offset) 2543{ 2544 return pemalloc(safe_address(nmemb, size, offset), 1); 2545} 2546 2547ZEND_API void *_safe_erealloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2548{ 2549 return erealloc_rel(ptr, safe_address(nmemb, size, offset)); 2550} 2551 2552ZEND_API void *_safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset) 2553{ 2554 return perealloc(ptr, safe_address(nmemb, size, offset), 1); 2555} 2556 2557 2558ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2559{ 2560 void *p; 2561#ifdef ZEND_SIGNALS 2562 TSRMLS_FETCH(); 2563#endif 2564 HANDLE_BLOCK_INTERRUPTIONS(); 2565 2566 p = _safe_emalloc(nmemb, size, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2567 if (UNEXPECTED(p == NULL)) { 2568 HANDLE_UNBLOCK_INTERRUPTIONS(); 2569 return p; 2570 } 2571 memset(p, 0, size * nmemb); 2572 HANDLE_UNBLOCK_INTERRUPTIONS(); 2573 return p; 2574} 2575 2576ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2577{ 2578 int length; 2579 char *p; 2580#ifdef ZEND_SIGNALS 2581 TSRMLS_FETCH(); 2582#endif 2583 2584 HANDLE_BLOCK_INTERRUPTIONS(); 2585 2586 length = strlen(s)+1; 2587 p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2588 if (UNEXPECTED(p == NULL)) { 2589 HANDLE_UNBLOCK_INTERRUPTIONS(); 2590 return p; 2591 } 2592 memcpy(p, s, length); 2593 HANDLE_UNBLOCK_INTERRUPTIONS(); 2594 return p; 2595} 2596 2597ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2598{ 2599 char *p; 2600#ifdef ZEND_SIGNALS 2601 TSRMLS_FETCH(); 2602#endif 2603 2604 HANDLE_BLOCK_INTERRUPTIONS(); 2605 2606 p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2607 if (UNEXPECTED(p == NULL)) { 2608 HANDLE_UNBLOCK_INTERRUPTIONS(); 2609 return p; 2610 } 2611 memcpy(p, s, length); 2612 p[length] = 0; 2613 HANDLE_UNBLOCK_INTERRUPTIONS(); 2614 return p; 2615} 2616 2617 2618ZEND_API char *zend_strndup(const char *s, uint length) 2619{ 2620 char *p; 2621#ifdef ZEND_SIGNALS 2622 TSRMLS_FETCH(); 2623#endif 2624 2625 HANDLE_BLOCK_INTERRUPTIONS(); 2626 2627 p = (char *) malloc(length+1); 2628 if (UNEXPECTED(p == NULL)) { 2629 HANDLE_UNBLOCK_INTERRUPTIONS(); 2630 return p; 2631 } 2632 if (length) { 2633 memcpy(p, s, length); 2634 } 2635 p[length] = 0; 2636 HANDLE_UNBLOCK_INTERRUPTIONS(); 2637 return p; 2638} 2639 2640 2641ZEND_API int zend_set_memory_limit(size_t memory_limit) 2642{ 2643 TSRMLS_FETCH(); 2644 2645 AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size; 2646 2647 return SUCCESS; 2648} 2649 2650ZEND_API size_t zend_memory_usage(int real_usage TSRMLS_DC) 2651{ 2652 if (real_usage) { 2653 return AG(mm_heap)->real_size; 2654 } else { 2655 size_t usage = AG(mm_heap)->size; 2656#if ZEND_MM_CACHE 2657 usage -= AG(mm_heap)->cached; 2658#endif 2659 return usage; 2660 } 2661} 2662 2663ZEND_API size_t zend_memory_peak_usage(int real_usage TSRMLS_DC) 2664{ 2665 if (real_usage) { 2666 return AG(mm_heap)->real_peak; 2667 } else { 2668 return AG(mm_heap)->peak; 2669 } 2670} 2671 2672ZEND_API void shutdown_memory_manager(int silent, int full_shutdown TSRMLS_DC) 2673{ 2674 zend_mm_shutdown(AG(mm_heap), full_shutdown, silent TSRMLS_CC); 2675} 2676 2677static void alloc_globals_ctor(zend_alloc_globals *alloc_globals TSRMLS_DC) 2678{ 2679 char *tmp = getenv("USE_ZEND_ALLOC"); 2680 2681 if (tmp && !zend_atoi(tmp, 0)) { 2682 alloc_globals->mm_heap = malloc(sizeof(struct _zend_mm_heap)); 2683 memset(alloc_globals->mm_heap, 0, sizeof(struct _zend_mm_heap)); 2684 alloc_globals->mm_heap->use_zend_alloc = 0; 2685 alloc_globals->mm_heap->_malloc = malloc; 2686 alloc_globals->mm_heap->_free = free; 2687 alloc_globals->mm_heap->_realloc = realloc; 2688 } else { 2689 alloc_globals->mm_heap = zend_mm_startup(); 2690 } 2691} 2692 2693#ifdef ZTS 2694static void alloc_globals_dtor(zend_alloc_globals *alloc_globals TSRMLS_DC) 2695{ 2696 shutdown_memory_manager(1, 1 TSRMLS_CC); 2697} 2698#endif 2699 2700ZEND_API void start_memory_manager(TSRMLS_D) 2701{ 2702#ifdef ZTS 2703 ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor); 2704#else 2705 alloc_globals_ctor(&alloc_globals); 2706#endif 2707} 2708 2709ZEND_API zend_mm_heap *zend_mm_set_heap(zend_mm_heap *new_heap TSRMLS_DC) 2710{ 2711 zend_mm_heap *old_heap; 2712 2713 old_heap = AG(mm_heap); 2714 AG(mm_heap) = new_heap; 2715 return old_heap; 2716} 2717 2718ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap) 2719{ 2720 return heap->storage; 2721} 2722 2723ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap, 2724 void* (*_malloc)(size_t), 2725 void (*_free)(void*), 2726 void* (*_realloc)(void*, size_t)) 2727{ 2728 heap->use_zend_alloc = 0; 2729 heap->_malloc = _malloc; 2730 heap->_free = _free; 2731 heap->_realloc = _realloc; 2732} 2733 2734#if ZEND_DEBUG 2735ZEND_API int _mem_block_check(void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2736{ 2737 TSRMLS_FETCH(); 2738 2739 if (!AG(mm_heap)->use_zend_alloc) { 2740 return 1; 2741 } 2742 return zend_mm_check_ptr(AG(mm_heap), ptr, silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2743} 2744 2745 2746ZEND_API void _full_mem_check(int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) 2747{ 2748 int errors; 2749 TSRMLS_FETCH(); 2750 2751 if (!AG(mm_heap)->use_zend_alloc) { 2752 return; 2753 } 2754 2755 zend_debug_alloc_output("------------------------------------------------\n"); 2756 zend_debug_alloc_output("Full Memory Check at %s:%d\n" ZEND_FILE_LINE_RELAY_CC); 2757 2758 errors = zend_mm_check_heap(AG(mm_heap), silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC); 2759 2760 zend_debug_alloc_output("End of full memory check %s:%d (%d errors)\n" ZEND_FILE_LINE_RELAY_CC, errors); 2761 zend_debug_alloc_output("------------------------------------------------\n"); 2762} 2763#endif 2764 2765/* 2766 * Local variables: 2767 * tab-width: 4 2768 * c-basic-offset: 4 2769 * indent-tabs-mode: t 2770 * End: 2771 */ 2772