Annotation of embedaddon/php/Zend/zend_alloc.c, revision 1.1.1.5

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

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