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