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