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