Annotation of embedaddon/php/Zend/zend_alloc_canary.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>