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