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