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