Annotation of embedaddon/php/Zend/zend_alloc.c, revision 1.1.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>