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