xref: /PHP-5.3/Zend/zend_alloc.c (revision e964817b)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) 1998-2013 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 	char *filename;
348 	uint lineno;
349 	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 #if ZEND_MM_CACHE_STAT
443 	struct {
444 		int count;
445 		int max_count;
446 		int hit;
447 		int miss;
448 	} cache_stat[ZEND_MM_NUM_BUCKETS+1];
449 #endif
450 };
451 
452 #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
453 	(zend_mm_free_block*) ((char*)&heap->free_buckets[index * 2] + \
454 		sizeof(zend_mm_free_block*) * 2 - \
455 		sizeof(zend_mm_small_free_block))
456 
457 #define ZEND_MM_REST_BUCKET(heap) \
458 	(zend_mm_free_block*)((char*)&heap->rest_buckets[0] + \
459 		sizeof(zend_mm_free_block*) * 2 - \
460 		sizeof(zend_mm_small_free_block))
461 
462 #if ZEND_MM_COOKIES
463 
464 static unsigned int _zend_mm_cookie = 0;
465 
466 # define ZEND_MM_COOKIE(block) \
467 	(((size_t)(block)) ^ _zend_mm_cookie)
468 # define ZEND_MM_SET_COOKIE(block) \
469 	(block)->info._cookie = ZEND_MM_COOKIE(block)
470 # define ZEND_MM_CHECK_COOKIE(block) \
471 	if (UNEXPECTED((block)->info._cookie != ZEND_MM_COOKIE(block))) { \
472 		zend_mm_panic("zend_mm_heap corrupted"); \
473 	}
474 #else
475 # define ZEND_MM_SET_COOKIE(block)
476 # define ZEND_MM_CHECK_COOKIE(block)
477 #endif
478 
479 /* Default memory segment size */
480 #define ZEND_MM_SEG_SIZE   (256 * 1024)
481 
482 /* Reserved space for error reporting in case of memory overflow */
483 #define ZEND_MM_RESERVE_SIZE            (8*1024)
484 
485 #ifdef _WIN64
486 # define ZEND_MM_LONG_CONST(x)	(x##i64)
487 #else
488 # define ZEND_MM_LONG_CONST(x)	(x##L)
489 #endif
490 
491 #define ZEND_MM_TYPE_MASK		ZEND_MM_LONG_CONST(0x3)
492 
493 #define ZEND_MM_FREE_BLOCK		ZEND_MM_LONG_CONST(0x0)
494 #define ZEND_MM_USED_BLOCK		ZEND_MM_LONG_CONST(0x1)
495 #define ZEND_MM_GUARD_BLOCK		ZEND_MM_LONG_CONST(0x3)
496 
497 #define ZEND_MM_BLOCK(b, type, size)	do { \
498 											size_t _size = (size); \
499 											(b)->info._size = (type) | _size; \
500 											ZEND_MM_BLOCK_AT(b, _size)->info._prev = (type) | _size; \
501 											ZEND_MM_SET_COOKIE(b); \
502 										} while (0);
503 #define ZEND_MM_LAST_BLOCK(b)			do { \
504 		(b)->info._size = ZEND_MM_GUARD_BLOCK | ZEND_MM_ALIGNED_HEADER_SIZE; \
505 		ZEND_MM_SET_MAGIC(b, MEM_BLOCK_GUARD); \
506  	} while (0);
507 #define ZEND_MM_BLOCK_SIZE(b)			((b)->info._size & ~ZEND_MM_TYPE_MASK)
508 #define ZEND_MM_IS_FREE_BLOCK(b)		(!((b)->info._size & ZEND_MM_USED_BLOCK))
509 #define ZEND_MM_IS_USED_BLOCK(b)		((b)->info._size & ZEND_MM_USED_BLOCK)
510 #define ZEND_MM_IS_GUARD_BLOCK(b)		(((b)->info._size & ZEND_MM_TYPE_MASK) == ZEND_MM_GUARD_BLOCK)
511 
512 #define ZEND_MM_NEXT_BLOCK(b)			ZEND_MM_BLOCK_AT(b, ZEND_MM_BLOCK_SIZE(b))
513 #define ZEND_MM_PREV_BLOCK(b)			ZEND_MM_BLOCK_AT(b, -(ssize_t)((b)->info._prev & ~ZEND_MM_TYPE_MASK))
514 
515 #define ZEND_MM_PREV_BLOCK_IS_FREE(b)	(!((b)->info._prev & ZEND_MM_USED_BLOCK))
516 
517 #define ZEND_MM_MARK_FIRST_BLOCK(b)		((b)->info._prev = ZEND_MM_GUARD_BLOCK)
518 #define ZEND_MM_IS_FIRST_BLOCK(b)		((b)->info._prev == ZEND_MM_GUARD_BLOCK)
519 
520 /* optimized access */
521 #define ZEND_MM_FREE_BLOCK_SIZE(b)		(b)->info._size
522 
523 /* Aligned header size */
524 #define ZEND_MM_ALIGNED_HEADER_SIZE			ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_block))
525 #define ZEND_MM_ALIGNED_FREE_HEADER_SIZE	ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_small_free_block))
526 #define ZEND_MM_MIN_ALLOC_BLOCK_SIZE		ZEND_MM_ALIGNED_SIZE(ZEND_MM_ALIGNED_HEADER_SIZE + END_MAGIC_SIZE)
527 #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)
528 #define ZEND_MM_ALIGNED_SEGMENT_SIZE		ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_segment))
529 
530 #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)
531 
532 #define ZEND_MM_MAX_SMALL_SIZE				((ZEND_MM_NUM_BUCKETS<<ZEND_MM_ALIGNMENT_LOG2)+ZEND_MM_ALIGNED_MIN_HEADER_SIZE)
533 
534 #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)))
535 
536 #define ZEND_MM_BUCKET_INDEX(true_size)		((true_size>>ZEND_MM_ALIGNMENT_LOG2)-(ZEND_MM_ALIGNED_MIN_HEADER_SIZE>>ZEND_MM_ALIGNMENT_LOG2))
537 
538 #define ZEND_MM_SMALL_SIZE(true_size)		(true_size < ZEND_MM_MAX_SMALL_SIZE)
539 
540 /* Memory calculations */
541 #define ZEND_MM_BLOCK_AT(blk, offset)	((zend_mm_block *) (((char *) (blk))+(offset)))
542 #define ZEND_MM_DATA_OF(p)				((void *) (((char *) (p))+ZEND_MM_ALIGNED_HEADER_SIZE))
543 #define ZEND_MM_HEADER_OF(blk)			ZEND_MM_BLOCK_AT(blk, -(int)ZEND_MM_ALIGNED_HEADER_SIZE)
544 
545 /* Debug output */
546 #if ZEND_DEBUG
547 
548 # ifdef ZTS
549 #  define ZEND_MM_SET_THREAD_ID(block) \
550 	((zend_mm_block*)(block))->thread_id = tsrm_thread_id()
551 #  define ZEND_MM_BAD_THREAD_ID(block) ((block)->thread_id != tsrm_thread_id())
552 # else
553 #  define ZEND_MM_SET_THREAD_ID(block)
554 #  define ZEND_MM_BAD_THREAD_ID(block) 0
555 # endif
556 
557 # define ZEND_MM_VALID_PTR(block) \
558 	zend_mm_check_ptr(heap, block, 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC)
559 
560 # define ZEND_MM_SET_MAGIC(block, val) do { \
561 		(block)->magic = (val); \
562 	} while (0)
563 
564 # define ZEND_MM_CHECK_MAGIC(block, val) do { \
565 		if ((block)->magic != (val)) { \
566 			zend_mm_panic("zend_mm_heap corrupted"); \
567 		} \
568 	} while (0)
569 
570 # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) do { \
571 		((zend_mm_block*)(block))->debug.filename = __zend_filename; \
572 		((zend_mm_block*)(block))->debug.lineno = __zend_lineno; \
573 		((zend_mm_block*)(block))->debug.orig_filename = __zend_orig_filename; \
574 		((zend_mm_block*)(block))->debug.orig_lineno = __zend_orig_lineno; \
575 		ZEND_MM_SET_BLOCK_SIZE(block, __size); \
576 		if (set_valid) { \
577 			ZEND_MM_SET_MAGIC(block, MEM_BLOCK_VALID); \
578 		} \
579 		if (set_thread) { \
580 			ZEND_MM_SET_THREAD_ID(block); \
581 		} \
582 	} while (0)
583 
584 #else
585 
586 # define ZEND_MM_VALID_PTR(ptr) EXPECTED(ptr != NULL)
587 
588 # define ZEND_MM_SET_MAGIC(block, val)
589 
590 # define ZEND_MM_CHECK_MAGIC(block, val)
591 
592 # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) ZEND_MM_SET_BLOCK_SIZE(block, __size)
593 
594 #endif
595 
596 
597 #if ZEND_MM_HEAP_PROTECTION
598 
599 # define ZEND_MM_CHECK_PROTECTION(block) \
600 	do { \
601 		if ((block)->debug.start_magic != _mem_block_start_magic || \
602 		    memcmp(ZEND_MM_END_MAGIC_PTR(block), &_mem_block_end_magic, END_MAGIC_SIZE) != 0) { \
603 		    zend_mm_panic("zend_mm_heap corrupted"); \
604 		} \
605 	} while (0)
606 
607 # define ZEND_MM_END_MAGIC_PTR(block) \
608 	(((char*)(ZEND_MM_DATA_OF(block))) + ((zend_mm_block*)(block))->debug.size)
609 
610 # define END_MAGIC_SIZE sizeof(unsigned int)
611 
612 # define ZEND_MM_SET_BLOCK_SIZE(block, __size) do { \
613 		char *p; \
614 		((zend_mm_block*)(block))->debug.size = (__size); \
615 		p = ZEND_MM_END_MAGIC_PTR(block); \
616 		((zend_mm_block*)(block))->debug.start_magic = _mem_block_start_magic; \
617 		memcpy(p, &_mem_block_end_magic, END_MAGIC_SIZE); \
618 	} while (0)
619 
620 static unsigned int _mem_block_start_magic = 0;
621 static unsigned int _mem_block_end_magic   = 0;
622 
623 #else
624 
625 # if ZEND_DEBUG
626 #  define ZEND_MM_SET_BLOCK_SIZE(block, _size) \
627 	((zend_mm_block*)(block))->debug.size = (_size)
628 # else
629 #  define ZEND_MM_SET_BLOCK_SIZE(block, _size)
630 # endif
631 
632 # define ZEND_MM_CHECK_PROTECTION(block)
633 
634 # define END_MAGIC_SIZE 0
635 
636 #endif
637 
638 #if ZEND_MM_SAFE_UNLINKING
639 # define ZEND_MM_CHECK_BLOCK_LINKAGE(block) \
640 	if (UNEXPECTED((block)->info._size != ZEND_MM_BLOCK_AT(block, ZEND_MM_FREE_BLOCK_SIZE(block))->info._prev) || \
641 		UNEXPECTED(!UNEXPECTED(ZEND_MM_IS_FIRST_BLOCK(block)) && \
642 	    UNEXPECTED(ZEND_MM_PREV_BLOCK(block)->info._size != (block)->info._prev))) { \
643 	    zend_mm_panic("zend_mm_heap corrupted"); \
644 	}
645 #define ZEND_MM_CHECK_TREE(block) \
646 	if (UNEXPECTED(*((block)->parent) != (block))) { \
647 		zend_mm_panic("zend_mm_heap corrupted"); \
648 	}
649 #else
650 # define ZEND_MM_CHECK_BLOCK_LINKAGE(block)
651 # define ZEND_MM_CHECK_TREE(block)
652 #endif
653 
654 #define ZEND_MM_LARGE_BUCKET_INDEX(S) zend_mm_high_bit(S)
655 
656 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;
657 static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
658 static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
659 
zend_mm_high_bit(size_t _size)660 static inline unsigned int zend_mm_high_bit(size_t _size)
661 {
662 #if defined(__GNUC__) && defined(i386)
663 	unsigned int n;
664 
665 	__asm__("bsrl %1,%0\n\t" : "=r" (n) : "rm"  (_size));
666 	return n;
667 #elif defined(__GNUC__) && defined(__x86_64__)
668 	unsigned long n;
669 
670         __asm__("bsrq %1,%0\n\t" : "=r" (n) : "rm"  (_size));
671         return (unsigned int)n;
672 #elif defined(_MSC_VER) && defined(_M_IX86)
673 	__asm {
674 		bsr eax, _size
675 	}
676 #else
677 	unsigned int n = 0;
678 	while (_size != 0) {
679 		_size = _size >> 1;
680 		n++;
681 	}
682 	return n-1;
683 #endif
684 }
685 
zend_mm_low_bit(size_t _size)686 static inline unsigned int zend_mm_low_bit(size_t _size)
687 {
688 #if defined(__GNUC__) && defined(i386)
689 	unsigned int n;
690 
691 	__asm__("bsfl %1,%0\n\t" : "=r" (n) : "rm"  (_size));
692 	return n;
693 #elif defined(__GNUC__) && defined(__x86_64__)
694         unsigned long n;
695 
696         __asm__("bsfq %1,%0\n\t" : "=r" (n) : "rm"  (_size));
697         return (unsigned int)n;
698 #elif defined(_MSC_VER) && defined(_M_IX86)
699 	__asm {
700 		bsf eax, _size
701    }
702 #else
703 	static const int offset[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
704 	unsigned int n;
705 	unsigned int index = 0;
706 
707 	n = offset[_size & 15];
708 	while (n == 4) {
709 		_size >>= 4;
710 		index += n;
711 		n = offset[_size & 15];
712 	}
713 
714 	return index + n;
715 #endif
716 }
717 
zend_mm_add_to_rest_list(zend_mm_heap * heap,zend_mm_free_block * mm_block)718 static inline void zend_mm_add_to_rest_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
719 {
720 	zend_mm_free_block *prev, *next;
721 
722 	ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
723 
724 	if (!ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block))) {
725 		mm_block->parent = NULL;
726 	}
727 
728 	prev = heap->rest_buckets[0];
729 	next = prev->next_free_block;
730 	mm_block->prev_free_block = prev;
731 	mm_block->next_free_block = next;
732 	prev->next_free_block = next->prev_free_block = mm_block;
733 }
734 
zend_mm_add_to_free_list(zend_mm_heap * heap,zend_mm_free_block * mm_block)735 static inline void zend_mm_add_to_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
736 {
737 	size_t size;
738 	size_t index;
739 
740 	ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
741 
742 	size = ZEND_MM_FREE_BLOCK_SIZE(mm_block);
743 	if (EXPECTED(!ZEND_MM_SMALL_SIZE(size))) {
744 		zend_mm_free_block **p;
745 
746 		index = ZEND_MM_LARGE_BUCKET_INDEX(size);
747 		p = &heap->large_free_buckets[index];
748 		mm_block->child[0] = mm_block->child[1] = NULL;
749 		if (!*p) {
750 			*p = mm_block;
751 			mm_block->parent = p;
752 			mm_block->prev_free_block = mm_block->next_free_block = mm_block;
753 			heap->large_free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
754 		} else {
755 			size_t m;
756 
757 			for (m = size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
758 				zend_mm_free_block *prev = *p;
759 
760 				if (ZEND_MM_FREE_BLOCK_SIZE(prev) != size) {
761 					p = &prev->child[(m >> (ZEND_MM_NUM_BUCKETS-1)) & 1];
762 					if (!*p) {
763 						*p = mm_block;
764 						mm_block->parent = p;
765 						mm_block->prev_free_block = mm_block->next_free_block = mm_block;
766 						break;
767 					}
768 				} else {
769 					zend_mm_free_block *next = prev->next_free_block;
770 
771 					prev->next_free_block = next->prev_free_block = mm_block;
772 					mm_block->next_free_block = next;
773 					mm_block->prev_free_block = prev;
774 					mm_block->parent = NULL;
775 					break;
776 				}
777 			}
778 		}
779 	} else {
780 		zend_mm_free_block *prev, *next;
781 
782 		index = ZEND_MM_BUCKET_INDEX(size);
783 
784 		prev = ZEND_MM_SMALL_FREE_BUCKET(heap, index);
785 		if (prev->prev_free_block == prev) {
786 			heap->free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
787 		}
788 		next = prev->next_free_block;
789 
790 		mm_block->prev_free_block = prev;
791 		mm_block->next_free_block = next;
792 		prev->next_free_block = next->prev_free_block = mm_block;
793 	}
794 }
795 
zend_mm_remove_from_free_list(zend_mm_heap * heap,zend_mm_free_block * mm_block)796 static inline void zend_mm_remove_from_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
797 {
798 	zend_mm_free_block *prev = mm_block->prev_free_block;
799 	zend_mm_free_block *next = mm_block->next_free_block;
800 
801 	ZEND_MM_CHECK_MAGIC(mm_block, MEM_BLOCK_FREED);
802 
803 	if (EXPECTED(prev == mm_block)) {
804 		zend_mm_free_block **rp, **cp;
805 
806 #if ZEND_MM_SAFE_UNLINKING
807 		if (UNEXPECTED(next != mm_block)) {
808 			zend_mm_panic("zend_mm_heap corrupted");
809 		}
810 #endif
811 
812 		rp = &mm_block->child[mm_block->child[1] != NULL];
813 		prev = *rp;
814 		if (EXPECTED(prev == NULL)) {
815 			size_t index = ZEND_MM_LARGE_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
816 
817 			ZEND_MM_CHECK_TREE(mm_block);
818 			*mm_block->parent = NULL;
819 			if (mm_block->parent == &heap->large_free_buckets[index]) {
820 				heap->large_free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
821 		    }
822 		} else {
823 			while (*(cp = &(prev->child[prev->child[1] != NULL])) != NULL) {
824 				prev = *cp;
825 				rp = cp;
826 			}
827 			*rp = NULL;
828 
829 subst_block:
830 			ZEND_MM_CHECK_TREE(mm_block);
831 			*mm_block->parent = prev;
832 			prev->parent = mm_block->parent;
833 			if ((prev->child[0] = mm_block->child[0])) {
834 				ZEND_MM_CHECK_TREE(prev->child[0]);
835 				prev->child[0]->parent = &prev->child[0];
836 			}
837 			if ((prev->child[1] = mm_block->child[1])) {
838 				ZEND_MM_CHECK_TREE(prev->child[1]);
839 				prev->child[1]->parent = &prev->child[1];
840 			}
841 		}
842 	} else {
843 
844 #if ZEND_MM_SAFE_UNLINKING
845 		if (UNEXPECTED(prev->next_free_block != mm_block) || UNEXPECTED(next->prev_free_block != mm_block)) {
846 			zend_mm_panic("zend_mm_heap corrupted");
847 		}
848 #endif
849 
850 		prev->next_free_block = next;
851 		next->prev_free_block = prev;
852 
853 		if (EXPECTED(ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block)))) {
854 			if (EXPECTED(prev == next)) {
855 				size_t index = ZEND_MM_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
856 
857 				if (EXPECTED(heap->free_buckets[index*2] == heap->free_buckets[index*2+1])) {
858 					heap->free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
859 				}
860 			}
861 		} else if (UNEXPECTED(mm_block->parent != NULL)) {
862 			goto subst_block;
863 		}
864 	}
865 }
866 
zend_mm_init(zend_mm_heap * heap)867 static inline void zend_mm_init(zend_mm_heap *heap)
868 {
869 	zend_mm_free_block* p;
870 	int i;
871 
872 	heap->free_bitmap = 0;
873 	heap->large_free_bitmap = 0;
874 #if ZEND_MM_CACHE
875 	heap->cached = 0;
876 	memset(heap->cache, 0, sizeof(heap->cache));
877 #endif
878 #if ZEND_MM_CACHE_STAT
879 	for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
880 		heap->cache_stat[i].count = 0;
881 	}
882 #endif
883 	p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
884 	for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
885 		p->next_free_block = p;
886 		p->prev_free_block = p;
887 		p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2);
888 		heap->large_free_buckets[i] = NULL;
889 	}
890 	heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap);
891 }
892 
zend_mm_del_segment(zend_mm_heap * heap,zend_mm_segment * segment)893 static void zend_mm_del_segment(zend_mm_heap *heap, zend_mm_segment *segment)
894 {
895 	zend_mm_segment **p = &heap->segments_list;
896 
897 	while (*p != segment) {
898 		p = &(*p)->next_segment;
899 	}
900 	*p = segment->next_segment;
901 	heap->real_size -= segment->size;
902 	ZEND_MM_STORAGE_FREE(segment);
903 }
904 
905 #if ZEND_MM_CACHE
zend_mm_free_cache(zend_mm_heap * heap)906 static void zend_mm_free_cache(zend_mm_heap *heap)
907 {
908 	int i;
909 
910 	for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
911 		if (heap->cache[i]) {
912 			zend_mm_free_block *mm_block = heap->cache[i];
913 
914 			while (mm_block) {
915 				size_t size = ZEND_MM_BLOCK_SIZE(mm_block);
916 				zend_mm_free_block *q = mm_block->prev_free_block;
917 				zend_mm_block *next_block = ZEND_MM_NEXT_BLOCK(mm_block);
918 
919 				heap->cached -= size;
920 
921 				if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) {
922 					mm_block = (zend_mm_free_block*)ZEND_MM_PREV_BLOCK(mm_block);
923 					size += ZEND_MM_FREE_BLOCK_SIZE(mm_block);
924 					zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block);
925 				}
926 				if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
927 					size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
928 					zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
929 				}
930 				ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size);
931 
932 				if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
933 				    ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_NEXT_BLOCK(mm_block))) {
934 					zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE));
935 				} else {
936 					zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block);
937 				}
938 
939 				mm_block = q;
940 			}
941 			heap->cache[i] = NULL;
942 #if ZEND_MM_CACHE_STAT
943 			heap->cache_stat[i].count = 0;
944 #endif
945 		}
946 	}
947 }
948 #endif
949 
950 #if ZEND_MM_HEAP_PROTECTION || ZEND_MM_COOKIES
zend_mm_random(unsigned char * buf,size_t size)951 static void zend_mm_random(unsigned char *buf, size_t size) /* {{{ */
952 {
953 	size_t i = 0;
954 	unsigned char t;
955 
956 #ifdef ZEND_WIN32
957 	HCRYPTPROV   hCryptProv;
958 	int has_context = 0;
959 
960 	if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) {
961 		/* Could mean that the key container does not exist, let try
962 		   again by asking for a new one */
963 		if (GetLastError() == NTE_BAD_KEYSET) {
964 			if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
965 				has_context = 1;
966 			}
967 		}
968 	} else {
969 		has_context = 1;
970 	}
971 	if (has_context) {
972 		do {
973 			BOOL ret = CryptGenRandom(hCryptProv, size, buf);
974 			CryptReleaseContext(hCryptProv, 0);
975 			if (ret) {
976 				while (i < size && buf[i] != 0) {
977 					i++;
978 				}
979 				if (i == size) {
980 					return;
981 				}
982 		   }
983 		} while (0);
984 	}
985 #elif defined(HAVE_DEV_URANDOM)
986 	int fd = open("/dev/urandom", 0);
987 
988 	if (fd >= 0) {
989 		if (read(fd, buf, size) == size) {
990 			while (i < size && buf[i] != 0) {
991 				i++;
992 			}
993 			if (i == size) {
994 				close(fd);
995 			    return;
996 			}
997 		}
998 		close(fd);
999 	}
1000 #endif
1001 	t = (unsigned char)getpid();
1002 	while (i < size) {
1003 		do {
1004 			buf[i] = ((unsigned char)rand()) ^ t;
1005 		} while (buf[i] == 0);
1006 		t = buf[i++] << 1;
1007     }
1008 }
1009 /* }}} */
1010 #endif
1011 
1012 /* Notes:
1013  * - This function may alter the block_sizes values to match platform alignment
1014  * - This function does *not* perform sanity checks on the arguments
1015  */
zend_mm_startup_ex(const zend_mm_mem_handlers * handlers,size_t block_size,size_t reserve_size,int internal,void * params)1016 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)
1017 {
1018 	zend_mm_storage *storage;
1019 	zend_mm_heap    *heap;
1020 
1021 #if 0
1022 	int i;
1023 
1024 	printf("ZEND_MM_ALIGNMENT=%d\n", ZEND_MM_ALIGNMENT);
1025 	printf("ZEND_MM_ALIGNMENT_LOG2=%d\n", ZEND_MM_ALIGNMENT_LOG2);
1026 	printf("ZEND_MM_MIN_SIZE=%d\n", ZEND_MM_MIN_SIZE);
1027 	printf("ZEND_MM_MAX_SMALL_SIZE=%d\n", ZEND_MM_MAX_SMALL_SIZE);
1028 	printf("ZEND_MM_ALIGNED_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_HEADER_SIZE);
1029 	printf("ZEND_MM_ALIGNED_FREE_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_FREE_HEADER_SIZE);
1030 	printf("ZEND_MM_MIN_ALLOC_BLOCK_SIZE=%d\n", ZEND_MM_MIN_ALLOC_BLOCK_SIZE);
1031 	printf("ZEND_MM_ALIGNED_MIN_HEADER_SIZE=%d\n", ZEND_MM_ALIGNED_MIN_HEADER_SIZE);
1032 	printf("ZEND_MM_ALIGNED_SEGMENT_SIZE=%d\n", ZEND_MM_ALIGNED_SEGMENT_SIZE);
1033 	for (i = 0; i < ZEND_MM_MAX_SMALL_SIZE; i++) {
1034 		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)));
1035 	}
1036 	exit(0);
1037 #endif
1038 
1039 #if ZEND_MM_HEAP_PROTECTION
1040 	if (_mem_block_start_magic == 0) {
1041 		zend_mm_random((unsigned char*)&_mem_block_start_magic, sizeof(_mem_block_start_magic));
1042 	}
1043 	if (_mem_block_end_magic == 0) {
1044 		zend_mm_random((unsigned char*)&_mem_block_end_magic, sizeof(_mem_block_end_magic));
1045 	}
1046 #endif
1047 #if ZEND_MM_COOKIES
1048 	if (_zend_mm_cookie == 0) {
1049 		zend_mm_random((unsigned char*)&_zend_mm_cookie, sizeof(_zend_mm_cookie));
1050 	}
1051 #endif
1052 
1053 	if (zend_mm_low_bit(block_size) != zend_mm_high_bit(block_size)) {
1054 		fprintf(stderr, "'block_size' must be a power of two\n");
1055 /* See http://support.microsoft.com/kb/190351 */
1056 #ifdef PHP_WIN32
1057 		fflush(stderr);
1058 #endif
1059 		exit(255);
1060 	}
1061 	storage = handlers->init(params);
1062 	if (!storage) {
1063 		fprintf(stderr, "Cannot initialize zend_mm storage [%s]\n", handlers->name);
1064 /* See http://support.microsoft.com/kb/190351 */
1065 #ifdef PHP_WIN32
1066 		fflush(stderr);
1067 #endif
1068 		exit(255);
1069 	}
1070 	storage->handlers = handlers;
1071 
1072 	heap = malloc(sizeof(struct _zend_mm_heap));
1073 	if (heap == NULL) {
1074 		fprintf(stderr, "Cannot allocate heap for zend_mm storage [%s]\n", handlers->name);
1075 #ifdef PHP_WIN32
1076 		fflush(stderr);
1077 #endif
1078 		exit(255);
1079 	}
1080 	heap->storage = storage;
1081 	heap->block_size = block_size;
1082 	heap->compact_size = 0;
1083 	heap->segments_list = NULL;
1084 	zend_mm_init(heap);
1085 # if ZEND_MM_CACHE_STAT
1086 	memset(heap->cache_stat, 0, sizeof(heap->cache_stat));
1087 # endif
1088 
1089 	heap->use_zend_alloc = 1;
1090 	heap->real_size = 0;
1091 	heap->overflow = 0;
1092 	heap->real_peak = 0;
1093 	heap->limit = ZEND_MM_LONG_CONST(1)<<(ZEND_MM_NUM_BUCKETS-2);
1094 	heap->size = 0;
1095 	heap->peak = 0;
1096 	heap->internal = internal;
1097 	heap->reserve = NULL;
1098 	heap->reserve_size = reserve_size;
1099 	if (reserve_size > 0) {
1100 		heap->reserve = _zend_mm_alloc_int(heap, reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
1101 	}
1102 	if (internal) {
1103 		int i;
1104 		zend_mm_free_block *p, *q, *orig;
1105 		zend_mm_heap *mm_heap = _zend_mm_alloc_int(heap, sizeof(zend_mm_heap)  ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
1106 
1107 		*mm_heap = *heap;
1108 
1109 		p = ZEND_MM_SMALL_FREE_BUCKET(mm_heap, 0);
1110 		orig = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
1111 		for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
1112 			q = p;
1113 			while (q->prev_free_block != orig) {
1114 				q = q->prev_free_block;
1115 			}
1116 			q->prev_free_block = p;
1117 			q = p;
1118 			while (q->next_free_block != orig) {
1119 				q = q->next_free_block;
1120 			}
1121 			q->next_free_block = p;
1122 			p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2);
1123 			orig = (zend_mm_free_block*)((char*)orig + sizeof(zend_mm_free_block*) * 2);
1124 			if (mm_heap->large_free_buckets[i]) {
1125 				mm_heap->large_free_buckets[i]->parent = &mm_heap->large_free_buckets[i];
1126 			}
1127 		}
1128 		mm_heap->rest_buckets[0] = mm_heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(mm_heap);
1129 
1130 		free(heap);
1131 		heap = mm_heap;
1132 	}
1133 	return heap;
1134 }
1135 
zend_mm_startup(void)1136 ZEND_API zend_mm_heap *zend_mm_startup(void)
1137 {
1138 	int i;
1139 	size_t seg_size;
1140 	char *mem_type = getenv("ZEND_MM_MEM_TYPE");
1141 	char *tmp;
1142 	const zend_mm_mem_handlers *handlers;
1143 	zend_mm_heap *heap;
1144 
1145 	if (mem_type == NULL) {
1146 		i = 0;
1147 	} else {
1148 		for (i = 0; mem_handlers[i].name; i++) {
1149 			if (strcmp(mem_handlers[i].name, mem_type) == 0) {
1150 				break;
1151 			}
1152 		}
1153 		if (!mem_handlers[i].name) {
1154 			fprintf(stderr, "Wrong or unsupported zend_mm storage type '%s'\n", mem_type);
1155 			fprintf(stderr, "  supported types:\n");
1156 /* See http://support.microsoft.com/kb/190351 */
1157 #ifdef PHP_WIN32
1158 			fflush(stderr);
1159 #endif
1160 			for (i = 0; mem_handlers[i].name; i++) {
1161 				fprintf(stderr, "    '%s'\n", mem_handlers[i].name);
1162 			}
1163 /* See http://support.microsoft.com/kb/190351 */
1164 #ifdef PHP_WIN32
1165 			fflush(stderr);
1166 #endif
1167 			exit(255);
1168 		}
1169 	}
1170 	handlers = &mem_handlers[i];
1171 
1172 	tmp = getenv("ZEND_MM_SEG_SIZE");
1173 	if (tmp) {
1174 		seg_size = zend_atoi(tmp, 0);
1175 		if (zend_mm_low_bit(seg_size) != zend_mm_high_bit(seg_size)) {
1176 			fprintf(stderr, "ZEND_MM_SEG_SIZE must be a power of two\n");
1177 /* See http://support.microsoft.com/kb/190351 */
1178 #ifdef PHP_WIN32
1179 			fflush(stderr);
1180 #endif
1181 			exit(255);
1182 		} else if (seg_size < ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE) {
1183 			fprintf(stderr, "ZEND_MM_SEG_SIZE is too small\n");
1184 /* See http://support.microsoft.com/kb/190351 */
1185 #ifdef PHP_WIN32
1186 			fflush(stderr);
1187 #endif
1188 			exit(255);
1189 		}
1190 	} else {
1191 		seg_size = ZEND_MM_SEG_SIZE;
1192 	}
1193 
1194 	heap = zend_mm_startup_ex(handlers, seg_size, ZEND_MM_RESERVE_SIZE, 0, NULL);
1195 	if (heap) {
1196 		tmp = getenv("ZEND_MM_COMPACT");
1197 		if (tmp) {
1198 			heap->compact_size = zend_atoi(tmp, 0);
1199 		} else {
1200 			heap->compact_size = 2 * 1024 * 1024;
1201 		}
1202 	}
1203 	return heap;
1204 }
1205 
1206 #if ZEND_DEBUG
zend_mm_find_leaks(zend_mm_segment * segment,zend_mm_block * b)1207 static long zend_mm_find_leaks(zend_mm_segment *segment, zend_mm_block *b)
1208 {
1209 	long leaks = 0;
1210 	zend_mm_block *p, *q;
1211 
1212 	p = ZEND_MM_NEXT_BLOCK(b);
1213 	while (1) {
1214 		if (ZEND_MM_IS_GUARD_BLOCK(p)) {
1215 			ZEND_MM_CHECK_MAGIC(p, MEM_BLOCK_GUARD);
1216 			segment = segment->next_segment;
1217 			if (!segment) {
1218 				break;
1219 			}
1220 			p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
1221 			continue;
1222 		}
1223 		q = ZEND_MM_NEXT_BLOCK(p);
1224 		if (q <= p ||
1225 		    (char*)q > (char*)segment + segment->size ||
1226 		    p->info._size != q->info._prev) {
1227 		    zend_mm_panic("zend_mm_heap corrupted");
1228 		}
1229 		if (!ZEND_MM_IS_FREE_BLOCK(p)) {
1230 			if (p->magic == MEM_BLOCK_VALID) {
1231 				if (p->debug.filename==b->debug.filename && p->debug.lineno==b->debug.lineno) {
1232 					ZEND_MM_SET_MAGIC(p, MEM_BLOCK_LEAK);
1233 					leaks++;
1234 				}
1235 #if ZEND_MM_CACHE
1236 			} else if (p->magic == MEM_BLOCK_CACHED) {
1237 				/* skip it */
1238 #endif
1239 			} else if (p->magic != MEM_BLOCK_LEAK) {
1240 			    zend_mm_panic("zend_mm_heap corrupted");
1241 			}
1242 		}
1243 		p = q;
1244 	}
1245 	return leaks;
1246 }
1247 
zend_mm_check_leaks(zend_mm_heap * heap TSRMLS_DC)1248 static void zend_mm_check_leaks(zend_mm_heap *heap TSRMLS_DC)
1249 {
1250 	zend_mm_segment *segment = heap->segments_list;
1251 	zend_mm_block *p, *q;
1252 	zend_uint total = 0;
1253 
1254 	if (!segment) {
1255 		return;
1256 	}
1257 	p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
1258 	while (1) {
1259 		q = ZEND_MM_NEXT_BLOCK(p);
1260 		if (q <= p ||
1261 		    (char*)q > (char*)segment + segment->size ||
1262 		    p->info._size != q->info._prev) {
1263 			zend_mm_panic("zend_mm_heap corrupted");
1264 		}
1265 		if (!ZEND_MM_IS_FREE_BLOCK(p)) {
1266 			if (p->magic == MEM_BLOCK_VALID) {
1267 				long repeated;
1268 				zend_leak_info leak;
1269 
1270 				ZEND_MM_SET_MAGIC(p, MEM_BLOCK_LEAK);
1271 
1272 				leak.addr = ZEND_MM_DATA_OF(p);
1273 				leak.size = p->debug.size;
1274 				leak.filename = p->debug.filename;
1275 				leak.lineno = p->debug.lineno;
1276 				leak.orig_filename = p->debug.orig_filename;
1277 				leak.orig_lineno = p->debug.orig_lineno;
1278 
1279 				zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC);
1280 				zend_message_dispatcher(ZMSG_MEMORY_LEAK_DETECTED, &leak TSRMLS_CC);
1281 				repeated = zend_mm_find_leaks(segment, p);
1282 				total += 1 + repeated;
1283 				if (repeated) {
1284 					zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *)(zend_uintptr_t)repeated TSRMLS_CC);
1285 				}
1286 #if ZEND_MM_CACHE
1287 			} else if (p->magic == MEM_BLOCK_CACHED) {
1288 				/* skip it */
1289 #endif
1290 			} else if (p->magic != MEM_BLOCK_LEAK) {
1291 				zend_mm_panic("zend_mm_heap corrupted");
1292 			}
1293 		}
1294 		if (ZEND_MM_IS_GUARD_BLOCK(q)) {
1295 			segment = segment->next_segment;
1296 			if (!segment) {
1297 				break;
1298 			}
1299 			q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
1300 		}
1301 		p = q;
1302 	}
1303 	if (total) {
1304 		zend_message_dispatcher(ZMSG_MEMORY_LEAKS_GRAND_TOTAL, &total TSRMLS_CC);
1305 	}
1306 }
1307 
zend_mm_check_ptr(zend_mm_heap * heap,void * ptr,int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)1308 static int zend_mm_check_ptr(zend_mm_heap *heap, void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
1309 {
1310 	zend_mm_block *p;
1311 	int no_cache_notice = 0;
1312 	int had_problems = 0;
1313 	int valid_beginning = 1;
1314 
1315 	if (silent==2) {
1316 		silent = 1;
1317 		no_cache_notice = 1;
1318 	} else if (silent==3) {
1319 		silent = 0;
1320 		no_cache_notice = 1;
1321 	}
1322 	if (!silent) {
1323 		TSRMLS_FETCH();
1324 
1325 		zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC);
1326 		zend_debug_alloc_output("---------------------------------------\n");
1327 		zend_debug_alloc_output("%s(%d) : Block "PTR_FMT" status:\n" ZEND_FILE_LINE_RELAY_CC, ptr);
1328 		if (__zend_orig_filename) {
1329 			zend_debug_alloc_output("%s(%d) : Actual location (location was relayed)\n" ZEND_FILE_LINE_ORIG_RELAY_CC);
1330 		}
1331 		if (!ptr) {
1332 			zend_debug_alloc_output("NULL\n");
1333 			zend_debug_alloc_output("---------------------------------------\n");
1334 			return 0;
1335 		}
1336 	}
1337 
1338 	if (!ptr) {
1339 		if (silent) {
1340 			return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1341 		}
1342 	}
1343 
1344 	p = ZEND_MM_HEADER_OF(ptr);
1345 
1346 #ifdef ZTS
1347 	if (ZEND_MM_BAD_THREAD_ID(p)) {
1348 		if (!silent) {
1349 			zend_debug_alloc_output("Invalid pointer: ((thread_id=0x%0.8X) != (expected=0x%0.8X))\n", (long)p->thread_id, (long)tsrm_thread_id());
1350 			had_problems = 1;
1351 		} else {
1352 			return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1353 		}
1354 	}
1355 #endif
1356 
1357 	if (p->info._size != ZEND_MM_NEXT_BLOCK(p)->info._prev) {
1358 		if (!silent) {
1359 			zend_debug_alloc_output("Invalid pointer: ((size="PTR_FMT") != (next.prev="PTR_FMT"))\n", p->info._size, ZEND_MM_NEXT_BLOCK(p)->info._prev);
1360 			had_problems = 1;
1361 		} else {
1362 			return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1363 		}
1364 	}
1365 	if (p->info._prev != ZEND_MM_GUARD_BLOCK &&
1366 	    ZEND_MM_PREV_BLOCK(p)->info._size != p->info._prev) {
1367 		if (!silent) {
1368 			zend_debug_alloc_output("Invalid pointer: ((prev="PTR_FMT") != (prev.size="PTR_FMT"))\n", p->info._prev, ZEND_MM_PREV_BLOCK(p)->info._size);
1369 			had_problems = 1;
1370 		} else {
1371 			return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1372 		}
1373 	}
1374 
1375 	if (had_problems) {
1376 		zend_debug_alloc_output("---------------------------------------\n");
1377 		return 0;
1378 	}
1379 
1380 	if (!silent) {
1381 		zend_debug_alloc_output("%10s\t","Beginning:  ");
1382 	}
1383 
1384 	if (!ZEND_MM_IS_USED_BLOCK(p)) {
1385 		if (!silent) {
1386 			if (p->magic != MEM_BLOCK_FREED) {
1387 				zend_debug_alloc_output("Freed (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
1388 			} else {
1389 				zend_debug_alloc_output("Freed\n");
1390 			}
1391 			had_problems = 1;
1392 		} else {
1393 			return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1394 		}
1395 	} else if (ZEND_MM_IS_GUARD_BLOCK(p)) {
1396 		if (!silent) {
1397 			if (p->magic != MEM_BLOCK_FREED) {
1398 				zend_debug_alloc_output("Guard (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
1399 			} else {
1400 				zend_debug_alloc_output("Guard\n");
1401 			}
1402 			had_problems = 1;
1403 		} else {
1404 			return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1405 		}
1406 	} else {
1407 		switch (p->magic) {
1408 			case MEM_BLOCK_VALID:
1409 			case MEM_BLOCK_LEAK:
1410 				if (!silent) {
1411 					zend_debug_alloc_output("OK (allocated on %s:%d, %d bytes)\n", p->debug.filename, p->debug.lineno, (int)p->debug.size);
1412 				}
1413 				break; /* ok */
1414 			case MEM_BLOCK_CACHED:
1415 				if (!no_cache_notice) {
1416 					if (!silent) {
1417 						zend_debug_alloc_output("Cached\n");
1418 						had_problems = 1;
1419 					} else {
1420 						return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1421 					}
1422 				}
1423 			case MEM_BLOCK_FREED:
1424 				if (!silent) {
1425 					zend_debug_alloc_output("Freed (invalid)\n");
1426 					had_problems = 1;
1427 				} else {
1428 					return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1429 				}
1430 				break;
1431 			case MEM_BLOCK_GUARD:
1432 				if (!silent) {
1433 					zend_debug_alloc_output("Guard (invalid)\n");
1434 					had_problems = 1;
1435 				} else {
1436 					return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1437 				}
1438 				break;
1439 			default:
1440 				if (!silent) {
1441 					zend_debug_alloc_output("Unknown (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_VALID);
1442 					had_problems = 1;
1443 					valid_beginning = 0;
1444 				} else {
1445 					return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1446 				}
1447 				break;
1448 		}
1449 	}
1450 
1451 #if ZEND_MM_HEAP_PROTECTION
1452 	if (!valid_beginning) {
1453 		if (!silent) {
1454 			zend_debug_alloc_output("%10s\t", "Start:");
1455 			zend_debug_alloc_output("Unknown\n");
1456 			zend_debug_alloc_output("%10s\t", "End:");
1457 			zend_debug_alloc_output("Unknown\n");
1458 		}
1459 	} else {
1460 		char *end_magic = ZEND_MM_END_MAGIC_PTR(p);
1461 
1462 		if (p->debug.start_magic == _mem_block_start_magic) {
1463 			if (!silent) {
1464 				zend_debug_alloc_output("%10s\t", "Start:");
1465 				zend_debug_alloc_output("OK\n");
1466 			}
1467 		} else {
1468 			char *overflow_ptr, *magic_ptr=(char *) &_mem_block_start_magic;
1469 			int overflows=0;
1470 			int i;
1471 
1472 			if (silent) {
1473 				return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1474 			}
1475 			had_problems = 1;
1476 			overflow_ptr = (char *) &p->debug.start_magic;
1477 			i = END_MAGIC_SIZE;
1478 			while (--i >= 0) {
1479 				if (overflow_ptr[i]!=magic_ptr[i]) {
1480 					overflows++;
1481 				}
1482 			}
1483 			zend_debug_alloc_output("%10s\t", "Start:");
1484 			zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", p->debug.start_magic, _mem_block_start_magic);
1485 			zend_debug_alloc_output("%10s\t","");
1486 			if (overflows >= END_MAGIC_SIZE) {
1487 				zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
1488 			} else {
1489 				zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
1490 			}
1491 		}
1492 		if (memcmp(end_magic, &_mem_block_end_magic, END_MAGIC_SIZE)==0) {
1493 			if (!silent) {
1494 				zend_debug_alloc_output("%10s\t", "End:");
1495 				zend_debug_alloc_output("OK\n");
1496 			}
1497 		} else {
1498 			char *overflow_ptr, *magic_ptr=(char *) &_mem_block_end_magic;
1499 			int overflows=0;
1500 			int i;
1501 
1502 			if (silent) {
1503 				return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1504 			}
1505 			had_problems = 1;
1506 			overflow_ptr = (char *) end_magic;
1507 
1508 			for (i=0; i < END_MAGIC_SIZE; i++) {
1509 				if (overflow_ptr[i]!=magic_ptr[i]) {
1510 					overflows++;
1511 				}
1512 			}
1513 
1514 			zend_debug_alloc_output("%10s\t", "End:");
1515 			zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", *end_magic, _mem_block_end_magic);
1516 			zend_debug_alloc_output("%10s\t","");
1517 			if (overflows >= END_MAGIC_SIZE) {
1518 				zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
1519 			} else {
1520 				zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
1521 			}
1522 		}
1523 	}
1524 #endif
1525 
1526 	if (!silent) {
1527 		zend_debug_alloc_output("---------------------------------------\n");
1528 	}
1529 	return ((!had_problems) ? 1 : 0);
1530 }
1531 
zend_mm_check_heap(zend_mm_heap * heap,int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)1532 static int zend_mm_check_heap(zend_mm_heap *heap, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
1533 {
1534 	zend_mm_segment *segment = heap->segments_list;
1535 	zend_mm_block *p, *q;
1536 	int errors = 0;
1537 
1538 	if (!segment) {
1539 		return 0;
1540 	}
1541 	p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
1542 	while (1) {
1543 		q = ZEND_MM_NEXT_BLOCK(p);
1544 		if (q <= p ||
1545 		    (char*)q > (char*)segment + segment->size ||
1546 		    p->info._size != q->info._prev) {
1547 			zend_mm_panic("zend_mm_heap corrupted");
1548 		}
1549 		if (!ZEND_MM_IS_FREE_BLOCK(p)) {
1550 			if (p->magic == MEM_BLOCK_VALID || p->magic == MEM_BLOCK_LEAK) {
1551 				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)) {
1552 					errors++;
1553 				}
1554 #if ZEND_MM_CACHE
1555 			} else if (p->magic == MEM_BLOCK_CACHED) {
1556 				/* skip it */
1557 #endif
1558 			} else if (p->magic != MEM_BLOCK_LEAK) {
1559 				zend_mm_panic("zend_mm_heap corrupted");
1560 			}
1561 		}
1562 		if (ZEND_MM_IS_GUARD_BLOCK(q)) {
1563 			segment = segment->next_segment;
1564 			if (!segment) {
1565 				return errors;
1566 			}
1567 			q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
1568 		}
1569 		p = q;
1570 	}
1571 }
1572 #endif
1573 
zend_mm_shutdown(zend_mm_heap * heap,int full_shutdown,int silent TSRMLS_DC)1574 ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, int full_shutdown, int silent TSRMLS_DC)
1575 {
1576 	zend_mm_storage *storage;
1577 	zend_mm_segment *segment;
1578 	zend_mm_segment *prev;
1579 	int internal;
1580 
1581 	if (heap->reserve) {
1582 #if ZEND_DEBUG
1583 		if (!silent) {
1584 			_zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
1585 		}
1586 #endif
1587 		heap->reserve = NULL;
1588 	}
1589 
1590 #if ZEND_MM_CACHE_STAT
1591 	if (full_shutdown) {
1592 		FILE *f;
1593 
1594 		f = fopen("zend_mm.log", "w");
1595 		if (f) {
1596 			int i,j;
1597 			size_t size, true_size, min_size, max_size;
1598 			int hit = 0, miss = 0;
1599 
1600 			fprintf(f, "\nidx min_size max_size true_size  max_len     hits   misses\n");
1601 			size = 0;
1602 			while (1) {
1603 				true_size = ZEND_MM_TRUE_SIZE(size);
1604 				if (ZEND_MM_SMALL_SIZE(true_size)) {
1605 					min_size = size;
1606 					i = ZEND_MM_BUCKET_INDEX(true_size);
1607 					size++;
1608 					while (1) {
1609 						true_size = ZEND_MM_TRUE_SIZE(size);
1610 						if (ZEND_MM_SMALL_SIZE(true_size)) {
1611 							j = ZEND_MM_BUCKET_INDEX(true_size);
1612 							if (j > i) {
1613 								max_size = size-1;
1614 								break;
1615 							}
1616 						} else {
1617 							max_size = size-1;
1618 							break;
1619 						}
1620 						size++;
1621 					}
1622 					hit += heap->cache_stat[i].hit;
1623 					miss += heap->cache_stat[i].miss;
1624 					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);
1625 				} else {
1626 					break;
1627 				}
1628 			}
1629 			fprintf(f, "                                        %8d %8d\n", hit, miss);
1630 			fprintf(f, "                                        %8d %8d\n", heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit, heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss);
1631 			fclose(f);
1632 		}
1633 	}
1634 #endif
1635 
1636 #if ZEND_DEBUG
1637 	if (!silent) {
1638 		zend_mm_check_leaks(heap TSRMLS_CC);
1639 	}
1640 #endif
1641 
1642 	internal = heap->internal;
1643 	storage = heap->storage;
1644 	segment = heap->segments_list;
1645 	while (segment) {
1646 		prev = segment;
1647 		segment = segment->next_segment;
1648 		ZEND_MM_STORAGE_FREE(prev);
1649 	}
1650 	if (full_shutdown) {
1651 		storage->handlers->dtor(storage);
1652 		if (!internal) {
1653 			free(heap);
1654 		}
1655 	} else {
1656 		if (heap->compact_size &&
1657 		    heap->real_peak > heap->compact_size) {
1658 			storage->handlers->compact(storage);
1659 		}
1660 		heap->segments_list = NULL;
1661 		zend_mm_init(heap);
1662 		heap->real_size = 0;
1663 		heap->real_peak = 0;
1664 		heap->size = 0;
1665 		heap->peak = 0;
1666 		if (heap->reserve_size) {
1667 			heap->reserve = _zend_mm_alloc_int(heap, heap->reserve_size  ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
1668 		}
1669 		heap->overflow = 0;
1670 	}
1671 }
1672 
zend_mm_safe_error(zend_mm_heap * heap,const char * format,size_t limit,const char * filename,uint lineno,size_t size)1673 static void zend_mm_safe_error(zend_mm_heap *heap,
1674 	const char *format,
1675 	size_t limit,
1676 #if ZEND_DEBUG
1677 	const char *filename,
1678 	uint lineno,
1679 #endif
1680 	size_t size)
1681 {
1682 	if (heap->reserve) {
1683 		_zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
1684 		heap->reserve = NULL;
1685 	}
1686 	if (heap->overflow == 0) {
1687 		char *error_filename;
1688 		uint error_lineno;
1689 		TSRMLS_FETCH();
1690 		if (zend_is_compiling(TSRMLS_C)) {
1691 			error_filename = zend_get_compiled_filename(TSRMLS_C);
1692 			error_lineno = zend_get_compiled_lineno(TSRMLS_C);
1693 		} else if (EG(in_execution)) {
1694 			error_filename = EG(active_op_array)?EG(active_op_array)->filename:NULL;
1695 			error_lineno = EG(opline_ptr)?(*EG(opline_ptr))->lineno:0;
1696 		} else {
1697 			error_filename = NULL;
1698 			error_lineno = 0;
1699 		}
1700 		if (!error_filename) {
1701 			error_filename = "Unknown";
1702 		}
1703 		heap->overflow = 1;
1704 		zend_try {
1705 			zend_error_noreturn(E_ERROR,
1706 				format,
1707 				limit,
1708 #if ZEND_DEBUG
1709 				filename,
1710 				lineno,
1711 #endif
1712 				size);
1713 		} zend_catch {
1714 			if (heap->overflow == 2) {
1715 				fprintf(stderr, "\nFatal error: ");
1716 				fprintf(stderr,
1717 					format,
1718 					limit,
1719 #if ZEND_DEBUG
1720 					filename,
1721 					lineno,
1722 #endif
1723 					size);
1724 				fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno);
1725 			}
1726 /* See http://support.microsoft.com/kb/190351 */
1727 #ifdef PHP_WIN32
1728 			fflush(stderr);
1729 #endif
1730 		} zend_end_try();
1731 	} else {
1732 		heap->overflow = 2;
1733 	}
1734 	zend_bailout();
1735 }
1736 
zend_mm_search_large_block(zend_mm_heap * heap,size_t true_size)1737 static zend_mm_free_block *zend_mm_search_large_block(zend_mm_heap *heap, size_t true_size)
1738 {
1739 	zend_mm_free_block *best_fit;
1740 	size_t index = ZEND_MM_LARGE_BUCKET_INDEX(true_size);
1741 	size_t bitmap = heap->large_free_bitmap >> index;
1742 	zend_mm_free_block *p;
1743 
1744 	if (bitmap == 0) {
1745 		return NULL;
1746 	}
1747 
1748 	if (UNEXPECTED((bitmap & 1) != 0)) {
1749 		/* Search for best "large" free block */
1750 		zend_mm_free_block *rst = NULL;
1751 		size_t m;
1752 		size_t best_size = -1;
1753 
1754 		best_fit = NULL;
1755 		p = heap->large_free_buckets[index];
1756 		for (m = true_size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
1757 			if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
1758 				return p->next_free_block;
1759 			} else if (ZEND_MM_FREE_BLOCK_SIZE(p) >= true_size &&
1760 			           ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
1761 				best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
1762 				best_fit = p;
1763 			}
1764 			if ((m & (ZEND_MM_LONG_CONST(1) << (ZEND_MM_NUM_BUCKETS-1))) == 0) {
1765 				if (p->child[1]) {
1766 					rst = p->child[1];
1767 				}
1768 				if (p->child[0]) {
1769 					p = p->child[0];
1770 				} else {
1771 					break;
1772 				}
1773 			} else if (p->child[1]) {
1774 				p = p->child[1];
1775 			} else {
1776 				break;
1777 			}
1778 		}
1779 
1780 		for (p = rst; p; p = p->child[p->child[0] != NULL]) {
1781 			if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
1782 				return p->next_free_block;
1783 			} else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
1784 			           ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
1785 				best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
1786 				best_fit = p;
1787 			}
1788 		}
1789 
1790 		if (best_fit) {
1791 			return best_fit->next_free_block;
1792 		}
1793 		bitmap = bitmap >> 1;
1794 		if (!bitmap) {
1795 			return NULL;
1796 		}
1797 		index++;
1798 	}
1799 
1800 	/* Search for smallest "large" free block */
1801 	best_fit = p = heap->large_free_buckets[index + zend_mm_low_bit(bitmap)];
1802 	while ((p = p->child[p->child[0] != NULL])) {
1803 		if (ZEND_MM_FREE_BLOCK_SIZE(p) < ZEND_MM_FREE_BLOCK_SIZE(best_fit)) {
1804 			best_fit = p;
1805 		}
1806 	}
1807 	return best_fit->next_free_block;
1808 }
1809 
_zend_mm_alloc_int(zend_mm_heap * heap,size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)1810 static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
1811 {
1812 	zend_mm_free_block *best_fit;
1813 	size_t true_size = ZEND_MM_TRUE_SIZE(size);
1814 	size_t block_size;
1815 	size_t remaining_size;
1816 	size_t segment_size;
1817 	zend_mm_segment *segment;
1818 	int keep_rest = 0;
1819 
1820 	if (EXPECTED(ZEND_MM_SMALL_SIZE(true_size))) {
1821 		size_t index = ZEND_MM_BUCKET_INDEX(true_size);
1822 		size_t bitmap;
1823 
1824 		if (UNEXPECTED(true_size < size)) {
1825 			goto out_of_memory;
1826 		}
1827 #if ZEND_MM_CACHE
1828 		if (EXPECTED(heap->cache[index] != NULL)) {
1829 			/* Get block from cache */
1830 #if ZEND_MM_CACHE_STAT
1831 			heap->cache_stat[index].count--;
1832 			heap->cache_stat[index].hit++;
1833 #endif
1834 			best_fit = heap->cache[index];
1835 			heap->cache[index] = best_fit->prev_free_block;
1836 			heap->cached -= true_size;
1837 			ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
1838 			ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
1839 			return ZEND_MM_DATA_OF(best_fit);
1840  		}
1841 #if ZEND_MM_CACHE_STAT
1842 		heap->cache_stat[index].miss++;
1843 #endif
1844 #endif
1845 
1846 		bitmap = heap->free_bitmap >> index;
1847 		if (bitmap) {
1848 			/* Found some "small" free block that can be used */
1849 			index += zend_mm_low_bit(bitmap);
1850 			best_fit = heap->free_buckets[index*2];
1851 #if ZEND_MM_CACHE_STAT
1852 			heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit++;
1853 #endif
1854 			goto zend_mm_finished_searching_for_block;
1855 		}
1856 	}
1857 
1858 #if ZEND_MM_CACHE_STAT
1859 	heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss++;
1860 #endif
1861 
1862 	best_fit = zend_mm_search_large_block(heap, true_size);
1863 
1864 	if (!best_fit && heap->real_size >= heap->limit - heap->block_size) {
1865 		zend_mm_free_block *p = heap->rest_buckets[0];
1866 		size_t best_size = -1;
1867 
1868 		while (p != ZEND_MM_REST_BUCKET(heap)) {
1869 			if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
1870 				best_fit = p;
1871 				goto zend_mm_finished_searching_for_block;
1872 			} else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
1873 			           ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
1874 				best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
1875 				best_fit = p;
1876 			}
1877 			p = p->prev_free_block;
1878 		}
1879 	}
1880 
1881 	if (!best_fit) {
1882 		if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
1883 			/* Make sure we add a memory block which is big enough,
1884 			   segment must have header "size" and trailer "guard" block */
1885 			segment_size = true_size + ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE;
1886 			segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
1887 			keep_rest = 1;
1888 		} else {
1889 			segment_size = heap->block_size;
1890 		}
1891 
1892 		HANDLE_BLOCK_INTERRUPTIONS();
1893 
1894 		if (segment_size < true_size ||
1895 		    heap->real_size + segment_size > heap->limit) {
1896 			/* Memory limit overflow */
1897 #if ZEND_MM_CACHE
1898 			zend_mm_free_cache(heap);
1899 #endif
1900 			HANDLE_UNBLOCK_INTERRUPTIONS();
1901 #if ZEND_DEBUG
1902 			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);
1903 #else
1904 			zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %lu bytes)", heap->limit, size);
1905 #endif
1906 		}
1907 
1908 		segment = (zend_mm_segment *) ZEND_MM_STORAGE_ALLOC(segment_size);
1909 
1910 		if (!segment) {
1911 			/* Storage manager cannot allocate memory */
1912 #if ZEND_MM_CACHE
1913 			zend_mm_free_cache(heap);
1914 #endif
1915 			HANDLE_UNBLOCK_INTERRUPTIONS();
1916 out_of_memory:
1917 #if ZEND_DEBUG
1918 			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);
1919 #else
1920 			zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %lu bytes)", heap->real_size, size);
1921 #endif
1922 			return NULL;
1923 		}
1924 
1925 		heap->real_size += segment_size;
1926 		if (heap->real_size > heap->real_peak) {
1927 			heap->real_peak = heap->real_size;
1928 		}
1929 
1930 		segment->size = segment_size;
1931 		segment->next_segment = heap->segments_list;
1932 		heap->segments_list = segment;
1933 
1934 		best_fit = (zend_mm_free_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
1935 		ZEND_MM_MARK_FIRST_BLOCK(best_fit);
1936 
1937 		block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
1938 
1939 		ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(best_fit, block_size));
1940 
1941 	} else {
1942 zend_mm_finished_searching_for_block:
1943 		/* remove from free list */
1944 		HANDLE_BLOCK_INTERRUPTIONS();
1945 		ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_FREED);
1946 		ZEND_MM_CHECK_COOKIE(best_fit);
1947 		ZEND_MM_CHECK_BLOCK_LINKAGE(best_fit);
1948 		zend_mm_remove_from_free_list(heap, best_fit);
1949 
1950 		block_size = ZEND_MM_FREE_BLOCK_SIZE(best_fit);
1951 	}
1952 
1953 	remaining_size = block_size - true_size;
1954 
1955 	if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
1956 		true_size = block_size;
1957 		ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
1958 	} else {
1959 		zend_mm_free_block *new_free_block;
1960 
1961 		/* prepare new free block */
1962 		ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
1963 		new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(best_fit, true_size);
1964 		ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
1965 
1966 		/* add the new free block to the free list */
1967 		if (EXPECTED(!keep_rest)) {
1968 			zend_mm_add_to_free_list(heap, new_free_block);
1969 		} else {
1970 			zend_mm_add_to_rest_list(heap, new_free_block);
1971 		}
1972 	}
1973 
1974 	ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 1);
1975 
1976 	heap->size += true_size;
1977 	if (heap->peak < heap->size) {
1978 		heap->peak = heap->size;
1979 	}
1980 
1981 	HANDLE_UNBLOCK_INTERRUPTIONS();
1982 
1983 	return ZEND_MM_DATA_OF(best_fit);
1984 }
1985 
1986 
_zend_mm_free_int(zend_mm_heap * heap,void * p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)1987 static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
1988 {
1989 	zend_mm_block *mm_block;
1990 	zend_mm_block *next_block;
1991 	size_t size;
1992 
1993 	if (!ZEND_MM_VALID_PTR(p)) {
1994 		return;
1995 	}
1996 
1997 	mm_block = ZEND_MM_HEADER_OF(p);
1998 	size = ZEND_MM_BLOCK_SIZE(mm_block);
1999 	ZEND_MM_CHECK_PROTECTION(mm_block);
2000 
2001 #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2002 	memset(ZEND_MM_DATA_OF(mm_block), 0x5a, mm_block->debug.size);
2003 #endif
2004 
2005 #if ZEND_MM_CACHE
2006 	if (EXPECTED(ZEND_MM_SMALL_SIZE(size)) && EXPECTED(heap->cached < ZEND_MM_CACHE_SIZE)) {
2007 		size_t index = ZEND_MM_BUCKET_INDEX(size);
2008 		zend_mm_free_block **cache = &heap->cache[index];
2009 
2010 		((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
2011 		*cache = (zend_mm_free_block*)mm_block;
2012 		heap->cached += size;
2013 		ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
2014 #if ZEND_MM_CACHE_STAT
2015 		if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
2016 			heap->cache_stat[index].max_count = heap->cache_stat[index].count;
2017 		}
2018 #endif
2019 		return;
2020 	}
2021 #endif
2022 
2023 	HANDLE_BLOCK_INTERRUPTIONS();
2024 
2025 	heap->size -= size;
2026 
2027 	next_block = ZEND_MM_BLOCK_AT(mm_block, size);
2028 	if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
2029 		zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
2030 		size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
2031 	}
2032 	if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) {
2033 		mm_block = ZEND_MM_PREV_BLOCK(mm_block);
2034 		zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block);
2035 		size += ZEND_MM_FREE_BLOCK_SIZE(mm_block);
2036 	}
2037 	if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
2038 	    ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(mm_block, size))) {
2039 		zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE));
2040 	} else {
2041 		ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size);
2042 		zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block);
2043 	}
2044 	HANDLE_UNBLOCK_INTERRUPTIONS();
2045 }
2046 
_zend_mm_realloc_int(zend_mm_heap * heap,void * p,size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2047 static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2048 {
2049 	zend_mm_block *mm_block = ZEND_MM_HEADER_OF(p);
2050 	zend_mm_block *next_block;
2051 	size_t true_size;
2052 	size_t orig_size;
2053 	void *ptr;
2054 
2055 	if (UNEXPECTED(!p) || !ZEND_MM_VALID_PTR(p)) {
2056 		return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2057 	}
2058 	mm_block = ZEND_MM_HEADER_OF(p);
2059 	true_size = ZEND_MM_TRUE_SIZE(size);
2060 	orig_size = ZEND_MM_BLOCK_SIZE(mm_block);
2061 	ZEND_MM_CHECK_PROTECTION(mm_block);
2062 
2063 	if (UNEXPECTED(true_size < size)) {
2064 		goto out_of_memory;
2065 	}
2066 
2067 	if (true_size <= orig_size) {
2068 		size_t remaining_size = orig_size - true_size;
2069 
2070 		if (remaining_size >= ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
2071 			zend_mm_free_block *new_free_block;
2072 
2073 			HANDLE_BLOCK_INTERRUPTIONS();
2074 			next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
2075 			if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
2076 				remaining_size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
2077 				zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
2078 			}
2079 
2080 			/* prepare new free block */
2081 			ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2082 			new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
2083 
2084 			ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
2085 
2086 			/* add the new free block to the free list */
2087 			zend_mm_add_to_free_list(heap, new_free_block);
2088 			heap->size += (true_size - orig_size);
2089 			HANDLE_UNBLOCK_INTERRUPTIONS();
2090 		}
2091 		ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
2092 		return p;
2093 	}
2094 
2095 #if ZEND_MM_CACHE
2096 	if (ZEND_MM_SMALL_SIZE(true_size)) {
2097 		size_t index = ZEND_MM_BUCKET_INDEX(true_size);
2098 
2099 		if (heap->cache[index] != NULL) {
2100 			zend_mm_free_block *best_fit;
2101 			zend_mm_free_block **cache;
2102 
2103 #if ZEND_MM_CACHE_STAT
2104 			heap->cache_stat[index].count--;
2105 			heap->cache_stat[index].hit++;
2106 #endif
2107 			best_fit = heap->cache[index];
2108 			heap->cache[index] = best_fit->prev_free_block;
2109 			ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
2110 			ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
2111 
2112 			ptr = ZEND_MM_DATA_OF(best_fit);
2113 
2114 #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2115 			memcpy(ptr, p, mm_block->debug.size);
2116 #else
2117 			memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
2118 #endif
2119 
2120 			heap->cached -= true_size - orig_size;
2121 
2122 			index = ZEND_MM_BUCKET_INDEX(orig_size);
2123 			cache = &heap->cache[index];
2124 
2125 			((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
2126 			*cache = (zend_mm_free_block*)mm_block;
2127 			ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
2128 #if ZEND_MM_CACHE_STAT
2129 			if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
2130 				heap->cache_stat[index].max_count = heap->cache_stat[index].count;
2131 			}
2132 #endif
2133 
2134 			return ptr;
2135 		}
2136 	}
2137 #endif
2138 
2139 	next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
2140 
2141 	if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
2142 		ZEND_MM_CHECK_COOKIE(next_block);
2143 		ZEND_MM_CHECK_BLOCK_LINKAGE(next_block);
2144 		if (orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block) >= true_size) {
2145 			size_t block_size = orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block);
2146 			size_t remaining_size = block_size - true_size;
2147 
2148 			HANDLE_BLOCK_INTERRUPTIONS();
2149 			zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
2150 
2151 			if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
2152 				true_size = block_size;
2153 				ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2154 			} else {
2155 				zend_mm_free_block *new_free_block;
2156 
2157 				/* prepare new free block */
2158 				ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2159 				new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
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 				if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
2164 				    ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(new_free_block, remaining_size))) {
2165 					zend_mm_add_to_rest_list(heap, new_free_block);
2166 				} else {
2167 					zend_mm_add_to_free_list(heap, new_free_block);
2168 				}
2169 			}
2170 			ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
2171 			heap->size = heap->size + true_size - orig_size;
2172 			if (heap->peak < heap->size) {
2173 				heap->peak = heap->size;
2174 			}
2175 			HANDLE_UNBLOCK_INTERRUPTIONS();
2176 			return p;
2177 		} else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
2178 				   ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(next_block, ZEND_MM_FREE_BLOCK_SIZE(next_block)))) {
2179 			HANDLE_BLOCK_INTERRUPTIONS();
2180 			zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
2181 			goto realloc_segment;
2182 		}
2183 	} else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && ZEND_MM_IS_GUARD_BLOCK(next_block)) {
2184 		zend_mm_segment *segment;
2185 		zend_mm_segment *segment_copy;
2186 		size_t segment_size;
2187 		size_t block_size;
2188 		size_t remaining_size;
2189 
2190 		HANDLE_BLOCK_INTERRUPTIONS();
2191 realloc_segment:
2192 		/* segment size, size of block and size of guard block */
2193 		if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
2194 			segment_size = true_size+ZEND_MM_ALIGNED_SEGMENT_SIZE+ZEND_MM_ALIGNED_HEADER_SIZE;
2195 			segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
2196 		} else {
2197 			segment_size = heap->block_size;
2198 		}
2199 
2200 		segment_copy = (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE);
2201 		if (segment_size < true_size ||
2202 		    heap->real_size + segment_size - segment_copy->size > heap->limit) {
2203 			if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
2204 				zend_mm_add_to_free_list(heap, (zend_mm_free_block *) next_block);
2205 			}
2206 #if ZEND_MM_CACHE
2207 			zend_mm_free_cache(heap);
2208 #endif
2209 			HANDLE_UNBLOCK_INTERRUPTIONS();
2210 #if ZEND_DEBUG
2211 			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);
2212 #else
2213 			zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %ld bytes)", heap->limit, size);
2214 #endif
2215 			return NULL;
2216 		}
2217 
2218 		segment = ZEND_MM_STORAGE_REALLOC(segment_copy, segment_size);
2219 		if (!segment) {
2220 #if ZEND_MM_CACHE
2221 			zend_mm_free_cache(heap);
2222 #endif
2223 			HANDLE_UNBLOCK_INTERRUPTIONS();
2224 out_of_memory:
2225 #if ZEND_DEBUG
2226 			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);
2227 #else
2228 			zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %ld bytes)", heap->real_size, size);
2229 #endif
2230 			return NULL;
2231 		}
2232 		heap->real_size += segment_size - segment->size;
2233 		if (heap->real_size > heap->real_peak) {
2234 			heap->real_peak = heap->real_size;
2235 		}
2236 
2237 		segment->size = segment_size;
2238 
2239 		if (segment != segment_copy) {
2240 			zend_mm_segment **seg = &heap->segments_list;
2241 			while (*seg != segment_copy) {
2242 				seg = &(*seg)->next_segment;
2243 			}
2244 			*seg = segment;
2245 			mm_block = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
2246 			ZEND_MM_MARK_FIRST_BLOCK(mm_block);
2247 		}
2248 
2249 		block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
2250 		remaining_size = block_size - true_size;
2251 
2252 		/* setup guard block */
2253 		ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(mm_block, block_size));
2254 
2255 		if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
2256 			true_size = block_size;
2257 			ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2258 		} else {
2259 			zend_mm_free_block *new_free_block;
2260 
2261 			/* prepare new free block */
2262 			ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2263 			new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
2264 			ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
2265 
2266 			/* add the new free block to the free list */
2267 			zend_mm_add_to_rest_list(heap, new_free_block);
2268 		}
2269 
2270 		ZEND_MM_SET_DEBUG_INFO(mm_block, size, 1, 1);
2271 
2272 		heap->size = heap->size + true_size - orig_size;
2273 		if (heap->peak < heap->size) {
2274 			heap->peak = heap->size;
2275 		}
2276 
2277 		HANDLE_UNBLOCK_INTERRUPTIONS();
2278 		return ZEND_MM_DATA_OF(mm_block);
2279 	}
2280 
2281 	ptr = _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2282 #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2283 	memcpy(ptr, p, mm_block->debug.size);
2284 #else
2285 	memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
2286 #endif
2287 	_zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2288 	return ptr;
2289 }
2290 
_zend_mm_alloc(zend_mm_heap * heap,size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2291 ZEND_API void *_zend_mm_alloc(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2292 {
2293 	return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2294 }
2295 
_zend_mm_free(zend_mm_heap * heap,void * p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2296 ZEND_API void _zend_mm_free(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2297 {
2298 	_zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2299 }
2300 
_zend_mm_realloc(zend_mm_heap * heap,void * ptr,size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2301 ZEND_API void *_zend_mm_realloc(zend_mm_heap *heap, void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2302 {
2303 	return _zend_mm_realloc_int(heap, ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2304 }
2305 
_zend_mm_block_size(zend_mm_heap * heap,void * p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2306 ZEND_API size_t _zend_mm_block_size(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2307 {
2308 	zend_mm_block *mm_block;
2309 
2310 	if (!ZEND_MM_VALID_PTR(p)) {
2311 		return 0;
2312 	}
2313 	mm_block = ZEND_MM_HEADER_OF(p);
2314 	ZEND_MM_CHECK_PROTECTION(mm_block);
2315 #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2316 	return mm_block->debug.size;
2317 #else
2318 	return ZEND_MM_BLOCK_SIZE(mm_block);
2319 #endif
2320 }
2321 
2322 /**********************/
2323 /* Allocation Manager */
2324 /**********************/
2325 
2326 typedef struct _zend_alloc_globals {
2327 	zend_mm_heap *mm_heap;
2328 } zend_alloc_globals;
2329 
2330 #ifdef ZTS
2331 static int alloc_globals_id;
2332 # define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v)
2333 #else
2334 # define AG(v) (alloc_globals.v)
2335 static zend_alloc_globals alloc_globals;
2336 #endif
2337 
is_zend_mm(TSRMLS_D)2338 ZEND_API int is_zend_mm(TSRMLS_D)
2339 {
2340 	return AG(mm_heap)->use_zend_alloc;
2341 }
2342 
_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2343 ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2344 {
2345 	TSRMLS_FETCH();
2346 
2347 	if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
2348 		return AG(mm_heap)->_malloc(size);
2349 	}
2350 	return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2351 }
2352 
_efree(void * ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2353 ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2354 {
2355 	TSRMLS_FETCH();
2356 
2357 	if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
2358 		AG(mm_heap)->_free(ptr);
2359 		return;
2360 	}
2361 	_zend_mm_free_int(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2362 }
2363 
_erealloc(void * ptr,size_t size,int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2364 ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2365 {
2366 	TSRMLS_FETCH();
2367 
2368 	if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
2369 		return AG(mm_heap)->_realloc(ptr, size);
2370 	}
2371 	return _zend_mm_realloc_int(AG(mm_heap), ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2372 }
2373 
_zend_mem_block_size(void * ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2374 ZEND_API size_t _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2375 {
2376 	if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
2377 		return 0;
2378 	}
2379 	return _zend_mm_block_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2380 }
2381 
2382 #if defined(__GNUC__) && defined(i386)
2383 
safe_address(size_t nmemb,size_t size,size_t offset)2384 static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
2385 {
2386 	size_t res = nmemb;
2387 	unsigned long overflow = 0;
2388 
2389 	__asm__ ("mull %3\n\taddl %4,%0\n\tadcl $0,%1"
2390 	     : "=&a"(res), "=&d" (overflow)
2391 	     : "%0"(res),
2392 	       "rm"(size),
2393 	       "rm"(offset));
2394 
2395 	if (UNEXPECTED(overflow)) {
2396 		zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2397 		return 0;
2398 	}
2399 	return res;
2400 }
2401 
2402 #elif defined(__GNUC__) && defined(__x86_64__)
2403 
safe_address(size_t nmemb,size_t size,size_t offset)2404 static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
2405 {
2406         size_t res = nmemb;
2407         unsigned long overflow = 0;
2408 
2409         __asm__ ("mulq %3\n\taddq %4,%0\n\tadcq $0,%1"
2410              : "=&a"(res), "=&d" (overflow)
2411              : "%0"(res),
2412                "rm"(size),
2413                "rm"(offset));
2414 
2415         if (UNEXPECTED(overflow)) {
2416                 zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2417                 return 0;
2418         }
2419         return res;
2420 }
2421 
2422 #elif SIZEOF_SIZE_T == 4 && defined(HAVE_ZEND_LONG64)
2423 
safe_address(size_t nmemb,size_t size,size_t offset)2424 static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
2425 {
2426 	zend_ulong64 res = (zend_ulong64)nmemb * (zend_ulong64)size + (zend_ulong64)offset;
2427 
2428 	if (UNEXPECTED(res > (zend_ulong64)0xFFFFFFFFL)) {
2429 		zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2430 		return 0;
2431 	}
2432 	return (size_t) res;
2433 }
2434 
2435 #else
2436 
safe_address(size_t nmemb,size_t size,size_t offset)2437 static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
2438 {
2439 	size_t res = nmemb * size + offset;
2440 	double _d  = (double)nmemb * (double)size + (double)offset;
2441 	double _delta = (double)res - _d;
2442 
2443 	if (UNEXPECTED((_d + _delta ) != _d)) {
2444 		zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2445 		return 0;
2446 	}
2447 	return res;
2448 }
2449 #endif
2450 
2451 
_safe_emalloc(size_t nmemb,size_t size,size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2452 ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2453 {
2454 	return emalloc_rel(safe_address(nmemb, size, offset));
2455 }
2456 
_safe_malloc(size_t nmemb,size_t size,size_t offset)2457 ZEND_API void *_safe_malloc(size_t nmemb, size_t size, size_t offset)
2458 {
2459 	return pemalloc(safe_address(nmemb, size, offset), 1);
2460 }
2461 
_safe_erealloc(void * ptr,size_t nmemb,size_t size,size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2462 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)
2463 {
2464 	return erealloc_rel(ptr, safe_address(nmemb, size, offset));
2465 }
2466 
_safe_realloc(void * ptr,size_t nmemb,size_t size,size_t offset)2467 ZEND_API void *_safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset)
2468 {
2469 	return perealloc(ptr, safe_address(nmemb, size, offset), 1);
2470 }
2471 
2472 
_ecalloc(size_t nmemb,size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2473 ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2474 {
2475 	void *p;
2476 
2477 	p = _safe_emalloc(nmemb, size, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2478 	if (UNEXPECTED(p == NULL)) {
2479 		return p;
2480 	}
2481 	memset(p, 0, size * nmemb);
2482 	return p;
2483 }
2484 
_estrdup(const char * s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2485 ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2486 {
2487 	int length;
2488 	char *p;
2489 
2490 	length = strlen(s)+1;
2491 	p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2492 	if (UNEXPECTED(p == NULL)) {
2493 		return p;
2494 	}
2495 	memcpy(p, s, length);
2496 	return p;
2497 }
2498 
_estrndup(const char * s,uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2499 ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2500 {
2501 	char *p;
2502 
2503 	p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2504 	if (UNEXPECTED(p == NULL)) {
2505 		return p;
2506 	}
2507 	memcpy(p, s, length);
2508 	p[length] = 0;
2509 	return p;
2510 }
2511 
2512 
zend_strndup(const char * s,uint length)2513 ZEND_API char *zend_strndup(const char *s, uint length)
2514 {
2515 	char *p;
2516 
2517 	p = (char *) malloc(length+1);
2518 	if (UNEXPECTED(p == NULL)) {
2519 		return p;
2520 	}
2521 	if (length) {
2522 		memcpy(p, s, length);
2523 	}
2524 	p[length] = 0;
2525 	return p;
2526 }
2527 
2528 
zend_set_memory_limit(size_t memory_limit)2529 ZEND_API int zend_set_memory_limit(size_t memory_limit)
2530 {
2531 	TSRMLS_FETCH();
2532 
2533 	AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size;
2534 
2535 	return SUCCESS;
2536 }
2537 
zend_memory_usage(int real_usage TSRMLS_DC)2538 ZEND_API size_t zend_memory_usage(int real_usage TSRMLS_DC)
2539 {
2540 	if (real_usage) {
2541 		return AG(mm_heap)->real_size;
2542 	} else {
2543 		size_t usage = AG(mm_heap)->size;
2544 #if ZEND_MM_CACHE
2545 		usage -= AG(mm_heap)->cached;
2546 #endif
2547 		return usage;
2548 	}
2549 }
2550 
zend_memory_peak_usage(int real_usage TSRMLS_DC)2551 ZEND_API size_t zend_memory_peak_usage(int real_usage TSRMLS_DC)
2552 {
2553 	if (real_usage) {
2554 		return AG(mm_heap)->real_peak;
2555 	} else {
2556 		return AG(mm_heap)->peak;
2557 	}
2558 }
2559 
shutdown_memory_manager(int silent,int full_shutdown TSRMLS_DC)2560 ZEND_API void shutdown_memory_manager(int silent, int full_shutdown TSRMLS_DC)
2561 {
2562 	zend_mm_shutdown(AG(mm_heap), full_shutdown, silent TSRMLS_CC);
2563 }
2564 
alloc_globals_ctor(zend_alloc_globals * alloc_globals TSRMLS_DC)2565 static void alloc_globals_ctor(zend_alloc_globals *alloc_globals TSRMLS_DC)
2566 {
2567 	char *tmp;
2568 	alloc_globals->mm_heap = zend_mm_startup();
2569 
2570 	tmp = getenv("USE_ZEND_ALLOC");
2571 	if (tmp) {
2572 		alloc_globals->mm_heap->use_zend_alloc = zend_atoi(tmp, 0);
2573 		if (!alloc_globals->mm_heap->use_zend_alloc) {
2574 			alloc_globals->mm_heap->_malloc = malloc;
2575 			alloc_globals->mm_heap->_free = free;
2576 			alloc_globals->mm_heap->_realloc = realloc;
2577 		}
2578 	}
2579 }
2580 
2581 #ifdef ZTS
alloc_globals_dtor(zend_alloc_globals * alloc_globals TSRMLS_DC)2582 static void alloc_globals_dtor(zend_alloc_globals *alloc_globals TSRMLS_DC)
2583 {
2584 	shutdown_memory_manager(1, 1 TSRMLS_CC);
2585 }
2586 #endif
2587 
start_memory_manager(TSRMLS_D)2588 ZEND_API void start_memory_manager(TSRMLS_D)
2589 {
2590 #ifdef ZTS
2591 	ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor);
2592 #else
2593 	alloc_globals_ctor(&alloc_globals);
2594 #endif
2595 }
2596 
zend_mm_set_heap(zend_mm_heap * new_heap TSRMLS_DC)2597 ZEND_API zend_mm_heap *zend_mm_set_heap(zend_mm_heap *new_heap TSRMLS_DC)
2598 {
2599 	zend_mm_heap *old_heap;
2600 
2601 	old_heap = AG(mm_heap);
2602 	AG(mm_heap) = new_heap;
2603 	return old_heap;
2604 }
2605 
zend_mm_get_storage(zend_mm_heap * heap)2606 ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap)
2607 {
2608 	return heap->storage;
2609 }
2610 
zend_mm_set_custom_handlers(zend_mm_heap * heap,void * (* _malloc)(size_t),void (* _free)(void *),void * (* _realloc)(void *,size_t))2611 ZEND_API void zend_mm_set_custom_handlers(zend_mm_heap *heap,
2612                                           void* (*_malloc)(size_t),
2613                                           void  (*_free)(void*),
2614                                           void* (*_realloc)(void*, size_t))
2615 {
2616 	heap->use_zend_alloc = 0;
2617 	heap->_malloc = _malloc;
2618 	heap->_free = _free;
2619 	heap->_realloc = _realloc;
2620 }
2621 
2622 #if ZEND_DEBUG
_mem_block_check(void * ptr,int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2623 ZEND_API int _mem_block_check(void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2624 {
2625 	TSRMLS_FETCH();
2626 
2627 	if (!AG(mm_heap)->use_zend_alloc) {
2628 		return 1;
2629 	}
2630 	return zend_mm_check_ptr(AG(mm_heap), ptr, silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2631 }
2632 
2633 
_full_mem_check(int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)2634 ZEND_API void _full_mem_check(int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2635 {
2636 	int errors;
2637 	TSRMLS_FETCH();
2638 
2639 	if (!AG(mm_heap)->use_zend_alloc) {
2640 		return;
2641 	}
2642 
2643 	zend_debug_alloc_output("------------------------------------------------\n");
2644 	zend_debug_alloc_output("Full Memory Check at %s:%d\n" ZEND_FILE_LINE_RELAY_CC);
2645 
2646 	errors = zend_mm_check_heap(AG(mm_heap), silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2647 
2648 	zend_debug_alloc_output("End of full memory check %s:%d (%d errors)\n" ZEND_FILE_LINE_RELAY_CC, errors);
2649 	zend_debug_alloc_output("------------------------------------------------\n");
2650 }
2651 #endif
2652 
2653 /*
2654  * Local variables:
2655  * tab-width: 4
2656  * c-basic-offset: 4
2657  * indent-tabs-mode: t
2658  * End:
2659  */
2660