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