Annotation of embedaddon/php/Zend/zend_alloc.c, revision 1.1.1.2
1.1 misho 1: /*
2: +----------------------------------------------------------------------+
3: | Zend Engine |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1998-2012 Zend Technologies Ltd. (http://www.zend.com) |
6: +----------------------------------------------------------------------+
7: | This source file is subject to version 2.00 of the Zend license, |
8: | that is bundled with this package in the file LICENSE, and is |
9: | available through the world-wide-web at the following url: |
10: | http://www.zend.com/license/2_00.txt. |
11: | If you did not receive a copy of the Zend license and are unable to |
12: | obtain it through the world-wide-web, please send a note to |
13: | license@zend.com so we can mail you a copy immediately. |
14: +----------------------------------------------------------------------+
15: | Authors: Andi Gutmans <andi@zend.com> |
16: | Zeev Suraski <zeev@zend.com> |
17: | Dmitry Stogov <dmitry@zend.com> |
18: +----------------------------------------------------------------------+
19: */
20:
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: {
667: #if defined(__GNUC__) && defined(i386)
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:
675: __asm__("bsrq %1,%0\n\t" : "=r" (n) : "rm" (_size));
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: {
693: #if defined(__GNUC__) && defined(i386)
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:
701: __asm__("bsfq %1,%0\n\t" : "=r" (n) : "rm" (_size));
702: return (unsigned int)n;
703: #elif defined(_MSC_VER) && defined(_M_IX86)
704: __asm {
705: bsf eax, _size
706: }
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:
2457: #if defined(__GNUC__) && defined(i386)
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:
2464: __asm__ ("mull %3\n\taddl %4,%0\n\tadcl %1,%1"
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:
2484: __asm__ ("mulq %3\n\taddq %4,%0\n\tadcq %1,%1"
2485: : "=&a"(res), "=&d" (overflow)
2486: : "%0"(res),
2487: "rm"(size),
2488: "rm"(offset));
2489:
2490: if (UNEXPECTED(overflow)) {
2491: zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2492: return 0;
2493: }
2494: return res;
2495: }
2496:
2497: #elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64)
2498:
2499: static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
2500: {
2501: zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset;
2502:
2503: if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) {
2504: zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2505: return 0;
2506: }
2507: return (size_t) res;
2508: }
2509:
2510: #else
2511:
2512: static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
2513: {
2514: size_t res = nmemb * size + offset;
2515: double _d = (double)nmemb * (double)size + (double)offset;
2516: double _delta = (double)res - _d;
2517:
2518: if (UNEXPECTED((_d + _delta ) != _d)) {
2519: zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2520: return 0;
2521: }
2522: return res;
2523: }
2524: #endif
2525:
1.1.1.2 ! misho 2526:
1.1 misho 2527: ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2528: {
2529: return emalloc_rel(safe_address(nmemb, size, offset));
2530: }
2531:
2532: ZEND_API void *_safe_malloc(size_t nmemb, size_t size, size_t offset)
2533: {
2534: return pemalloc(safe_address(nmemb, size, offset), 1);
2535: }
2536:
2537: 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)
2538: {
2539: return erealloc_rel(ptr, safe_address(nmemb, size, offset));
2540: }
2541:
2542: ZEND_API void *_safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset)
2543: {
2544: return perealloc(ptr, safe_address(nmemb, size, offset), 1);
2545: }
2546:
2547:
2548: ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2549: {
2550: void *p;
1.1.1.2 ! misho 2551: #ifdef ZEND_SIGNALS
! 2552: TSRMLS_FETCH();
! 2553: #endif
! 2554: HANDLE_BLOCK_INTERRUPTIONS();
1.1 misho 2555:
2556: p = _safe_emalloc(nmemb, size, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2557: if (UNEXPECTED(p == NULL)) {
1.1.1.2 ! misho 2558: HANDLE_UNBLOCK_INTERRUPTIONS();
1.1 misho 2559: return p;
2560: }
2561: memset(p, 0, size * nmemb);
1.1.1.2 ! misho 2562: HANDLE_UNBLOCK_INTERRUPTIONS();
1.1 misho 2563: return p;
2564: }
2565:
2566: ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2567: {
2568: int length;
2569: char *p;
1.1.1.2 ! misho 2570: #ifdef ZEND_SIGNALS
! 2571: TSRMLS_FETCH();
! 2572: #endif
! 2573:
! 2574: HANDLE_BLOCK_INTERRUPTIONS();
1.1 misho 2575:
2576: length = strlen(s)+1;
2577: p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2578: if (UNEXPECTED(p == NULL)) {
1.1.1.2 ! misho 2579: HANDLE_UNBLOCK_INTERRUPTIONS();
1.1 misho 2580: return p;
2581: }
2582: memcpy(p, s, length);
1.1.1.2 ! misho 2583: HANDLE_UNBLOCK_INTERRUPTIONS();
1.1 misho 2584: return p;
2585: }
2586:
2587: ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2588: {
2589: char *p;
1.1.1.2 ! misho 2590: #ifdef ZEND_SIGNALS
! 2591: TSRMLS_FETCH();
! 2592: #endif
! 2593:
! 2594: HANDLE_BLOCK_INTERRUPTIONS();
1.1 misho 2595:
2596: p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2597: if (UNEXPECTED(p == NULL)) {
1.1.1.2 ! misho 2598: HANDLE_UNBLOCK_INTERRUPTIONS();
1.1 misho 2599: return p;
2600: }
2601: memcpy(p, s, length);
2602: p[length] = 0;
1.1.1.2 ! misho 2603: HANDLE_UNBLOCK_INTERRUPTIONS();
1.1 misho 2604: return p;
2605: }
2606:
2607:
2608: ZEND_API char *zend_strndup(const char *s, uint length)
2609: {
2610: char *p;
1.1.1.2 ! misho 2611: #ifdef ZEND_SIGNALS
! 2612: TSRMLS_FETCH();
! 2613: #endif
! 2614:
! 2615: HANDLE_BLOCK_INTERRUPTIONS();
1.1 misho 2616:
2617: p = (char *) malloc(length+1);
2618: if (UNEXPECTED(p == NULL)) {
1.1.1.2 ! misho 2619: HANDLE_UNBLOCK_INTERRUPTIONS();
1.1 misho 2620: return p;
2621: }
2622: if (length) {
2623: memcpy(p, s, length);
2624: }
2625: p[length] = 0;
1.1.1.2 ! misho 2626: HANDLE_UNBLOCK_INTERRUPTIONS();
1.1 misho 2627: return p;
2628: }
2629:
2630:
2631: ZEND_API int zend_set_memory_limit(size_t memory_limit)
2632: {
2633: TSRMLS_FETCH();
2634:
2635: AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size;
2636:
2637: return SUCCESS;
2638: }
2639:
2640: ZEND_API size_t zend_memory_usage(int real_usage TSRMLS_DC)
2641: {
2642: if (real_usage) {
2643: return AG(mm_heap)->real_size;
2644: } else {
2645: size_t usage = AG(mm_heap)->size;
2646: #if ZEND_MM_CACHE
2647: usage -= AG(mm_heap)->cached;
2648: #endif
2649: return usage;
2650: }
2651: }
2652:
2653: ZEND_API size_t zend_memory_peak_usage(int real_usage TSRMLS_DC)
2654: {
2655: if (real_usage) {
2656: return AG(mm_heap)->real_peak;
2657: } else {
2658: return AG(mm_heap)->peak;
2659: }
2660: }
2661:
2662: ZEND_API void shutdown_memory_manager(int silent, int full_shutdown TSRMLS_DC)
2663: {
2664: zend_mm_shutdown(AG(mm_heap), full_shutdown, silent TSRMLS_CC);
2665: }
2666:
2667: static void alloc_globals_ctor(zend_alloc_globals *alloc_globals TSRMLS_DC)
2668: {
1.1.1.2 ! misho 2669: char *tmp = getenv("USE_ZEND_ALLOC");
1.1 misho 2670:
1.1.1.2 ! misho 2671: if (tmp && !zend_atoi(tmp, 0)) {
! 2672: alloc_globals->mm_heap = malloc(sizeof(struct _zend_mm_heap));
! 2673: memset(alloc_globals->mm_heap, 0, sizeof(struct _zend_mm_heap));
! 2674: alloc_globals->mm_heap->use_zend_alloc = 0;
! 2675: alloc_globals->mm_heap->_malloc = malloc;
! 2676: alloc_globals->mm_heap->_free = free;
! 2677: alloc_globals->mm_heap->_realloc = realloc;
! 2678: } else {
! 2679: alloc_globals->mm_heap = zend_mm_startup();
1.1 misho 2680: }
2681: }
2682:
2683: #ifdef ZTS
2684: static void alloc_globals_dtor(zend_alloc_globals *alloc_globals TSRMLS_DC)
2685: {
2686: shutdown_memory_manager(1, 1 TSRMLS_CC);
2687: }
2688: #endif
2689:
2690: ZEND_API void start_memory_manager(TSRMLS_D)
2691: {
2692: #ifdef ZTS
2693: ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor);
2694: #else
2695: alloc_globals_ctor(&alloc_globals);
2696: #endif
2697: }
2698:
2699: ZEND_API zend_mm_heap *zend_mm_set_heap(zend_mm_heap *new_heap TSRMLS_DC)
2700: {
2701: zend_mm_heap *old_heap;
2702:
2703: old_heap = AG(mm_heap);
2704: AG(mm_heap) = new_heap;
2705: return old_heap;
2706: }
2707:
2708: ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap)
2709: {
2710: return heap->storage;
2711: }
2712:
2713: ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
2714: void* (*_malloc)(size_t),
2715: void (*_free)(void*),
2716: void* (*_realloc)(void*, size_t))
2717: {
2718: heap->use_zend_alloc = 0;
2719: heap->_malloc = _malloc;
2720: heap->_free = _free;
2721: heap->_realloc = _realloc;
2722: }
2723:
2724: #if ZEND_DEBUG
2725: ZEND_API int _mem_block_check(void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2726: {
2727: TSRMLS_FETCH();
2728:
2729: if (!AG(mm_heap)->use_zend_alloc) {
2730: return 1;
2731: }
2732: return zend_mm_check_ptr(AG(mm_heap), ptr, silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2733: }
2734:
2735:
2736: ZEND_API void _full_mem_check(int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2737: {
2738: int errors;
2739: TSRMLS_FETCH();
2740:
2741: if (!AG(mm_heap)->use_zend_alloc) {
2742: return;
2743: }
2744:
2745: zend_debug_alloc_output("------------------------------------------------\n");
2746: zend_debug_alloc_output("Full Memory Check at %s:%d\n" ZEND_FILE_LINE_RELAY_CC);
2747:
2748: errors = zend_mm_check_heap(AG(mm_heap), silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2749:
2750: zend_debug_alloc_output("End of full memory check %s:%d (%d errors)\n" ZEND_FILE_LINE_RELAY_CC, errors);
2751: zend_debug_alloc_output("------------------------------------------------\n");
2752: }
2753: #endif
2754:
2755: /*
2756: * Local variables:
2757: * tab-width: 4
2758: * c-basic-offset: 4
2759: * indent-tabs-mode: t
2760: * End:
2761: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>