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 281439 2009-05-30 16:42:24Z lbarnaud $ */
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 : # define _WIN32_WINNT 0x0400
37 : # include <wincrypt.h>
38 : # include <process.h>
39 : #endif
40 :
41 : #ifndef ZEND_MM_HEAP_PROTECTION
42 : # define ZEND_MM_HEAP_PROTECTION ZEND_DEBUG
43 : #endif
44 :
45 : #ifndef ZEND_MM_SAFE_UNLINKING
46 : # define ZEND_MM_SAFE_UNLINKING 1
47 : #endif
48 :
49 : #ifndef ZEND_MM_COOKIES
50 : # define ZEND_MM_COOKIES ZEND_DEBUG
51 : #endif
52 :
53 : #ifdef _WIN64
54 : # define PTR_FMT "0x%0.16I64x"
55 : /*
56 : #elif sizeof(long) == 8
57 : # define PTR_FMT "0x%0.16lx"
58 : */
59 : #else
60 : # define PTR_FMT "0x%0.8lx"
61 : #endif
62 :
63 : #if ZEND_DEBUG
64 : void zend_debug_alloc_output(char *format, ...)
65 : {
66 : char output_buf[256];
67 : va_list args;
68 :
69 : va_start(args, format);
70 : vsprintf(output_buf, format, args);
71 : va_end(args);
72 :
73 : #ifdef ZEND_WIN32
74 : OutputDebugString(output_buf);
75 : #else
76 : fprintf(stderr, "%s", output_buf);
77 : #endif
78 : }
79 : #endif
80 :
81 : #if (defined (__GNUC__) && __GNUC__ > 2 ) && !defined(__INTEL_COMPILER) && !defined(DARWIN) && !defined(__hpux) && !defined(_AIX)
82 : # define EXPECTED(condition) __builtin_expect(condition, 1)
83 : # define UNEXPECTED(condition) __builtin_expect(condition, 0)
84 : static void zend_mm_panic(const char *message) __attribute__ ((noreturn));
85 : #else
86 : # define EXPECTED(condition) (condition)
87 : # define UNEXPECTED(condition) (condition)
88 : #endif
89 :
90 : static void zend_mm_panic(const char *message)
91 0 : {
92 0 : fprintf(stderr, "%s\n", message);
93 : #if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID)
94 : kill(getpid(), SIGSEGV);
95 : #endif
96 0 : exit(1);
97 : }
98 :
99 : /*******************/
100 : /* Storage Manager */
101 : /*******************/
102 :
103 : #ifdef ZEND_WIN32
104 : # define HAVE_MEM_WIN32 /* use VirtualAlloc() to allocate memory */
105 : #endif
106 : #define HAVE_MEM_MALLOC /* use malloc() to allocate segments */
107 :
108 : #include <sys/types.h>
109 : #include <sys/stat.h>
110 : #if HAVE_LIMITS_H
111 : #include <limits.h>
112 : #endif
113 : #include <fcntl.h>
114 : #include <errno.h>
115 :
116 : #if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
117 : # ifdef HAVE_MREMAP
118 : # define _GNU_SOURCE
119 : # define __USE_GNU
120 : # endif
121 : # include <sys/mman.h>
122 : # ifndef MAP_ANON
123 : # ifdef MAP_ANONYMOUS
124 : # define MAP_ANON MAP_ANONYMOUS
125 : # endif
126 : # endif
127 : # ifndef MREMAP_MAYMOVE
128 : # define MREMAP_MAYMOVE 0
129 : # endif
130 : # ifndef MAP_FAILED
131 : # define MAP_FAILED ((void*)-1)
132 : # endif
133 : #endif
134 :
135 : static zend_mm_storage* zend_mm_mem_dummy_init(void *params)
136 13565 : {
137 13565 : return malloc(sizeof(zend_mm_storage));
138 : }
139 :
140 : static void zend_mm_mem_dummy_dtor(zend_mm_storage *storage)
141 13597 : {
142 13597 : free(storage);
143 13597 : }
144 :
145 : #if defined(HAVE_MEM_MMAP_ANON) || defined(HAVE_MEM_MMAP_ZERO)
146 :
147 : static zend_mm_segment* zend_mm_mem_mmap_realloc(zend_mm_storage *storage, zend_mm_segment* segment, size_t size)
148 0 : {
149 : zend_mm_segment *ret;
150 : #ifdef HAVE_MREMAP
151 : #if defined(__NetBSD__)
152 : /* NetBSD 5 supports mremap but takes an extra newp argument */
153 : ret = (zend_mm_segment*)mremap(segment, segment->size, segment, size, MREMAP_MAYMOVE);
154 : #else
155 0 : ret = (zend_mm_segment*)mremap(segment, segment->size, size, MREMAP_MAYMOVE);
156 : #endif
157 0 : if (ret == MAP_FAILED) {
158 : #endif
159 0 : ret = storage->handlers->_alloc(storage, size);
160 0 : if (ret) {
161 0 : memcpy(ret, segment, size > segment->size ? segment->size : size);
162 0 : storage->handlers->_free(storage, segment);
163 : }
164 : #ifdef HAVE_MREMAP
165 : }
166 : #endif
167 0 : return ret;
168 : }
169 :
170 : static void zend_mm_mem_mmap_free(zend_mm_storage *storage, zend_mm_segment* segment)
171 0 : {
172 0 : munmap((void*)segment, segment->size);
173 0 : }
174 :
175 : #endif
176 :
177 : #ifdef HAVE_MEM_MMAP_ANON
178 :
179 : static zend_mm_segment* zend_mm_mem_mmap_anon_alloc(zend_mm_storage *storage, size_t size)
180 0 : {
181 0 : zend_mm_segment *ret = (zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
182 0 : if (ret == MAP_FAILED) {
183 0 : ret = NULL;
184 : }
185 0 : return ret;
186 : }
187 :
188 : # define ZEND_MM_MEM_MMAP_ANON_DSC {"mmap_anon", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_mmap_anon_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
189 :
190 : #endif
191 :
192 : #ifdef HAVE_MEM_MMAP_ZERO
193 :
194 : static int zend_mm_dev_zero_fd = -1;
195 :
196 : static zend_mm_storage* zend_mm_mem_mmap_zero_init(void *params)
197 0 : {
198 0 : if (zend_mm_dev_zero_fd != -1) {
199 0 : zend_mm_dev_zero_fd = open("/dev/zero", O_RDWR, S_IRUSR | S_IWUSR);
200 : }
201 0 : if (zend_mm_dev_zero_fd >= 0) {
202 0 : return malloc(sizeof(zend_mm_storage));
203 : } else {
204 0 : return NULL;
205 : }
206 : }
207 :
208 : static void zend_mm_mem_mmap_zero_dtor(zend_mm_storage *storage)
209 0 : {
210 0 : close(zend_mm_dev_zero_fd);
211 0 : free(storage);
212 0 : }
213 :
214 : static zend_mm_segment* zend_mm_mem_mmap_zero_alloc(zend_mm_storage *storage, size_t size)
215 0 : {
216 0 : zend_mm_segment *ret = (zend_mm_segment*)mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, zend_mm_dev_zero_fd, 0);
217 0 : if (ret == MAP_FAILED) {
218 0 : ret = NULL;
219 : }
220 0 : return ret;
221 : }
222 :
223 : # define ZEND_MM_MEM_MMAP_ZERO_DSC {"mmap_zero", zend_mm_mem_mmap_zero_init, zend_mm_mem_mmap_zero_dtor, zend_mm_mem_mmap_zero_alloc, zend_mm_mem_mmap_realloc, zend_mm_mem_mmap_free}
224 :
225 : #endif
226 :
227 : #ifdef HAVE_MEM_WIN32
228 :
229 : static zend_mm_storage* zend_mm_mem_win32_init(void *params)
230 : {
231 : HANDLE heap = HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
232 : zend_mm_storage* storage;
233 :
234 : if (heap == NULL) {
235 : return NULL;
236 : }
237 : storage = (zend_mm_storage*)malloc(sizeof(zend_mm_storage));
238 : storage->data = (void*) heap;
239 : return storage;
240 : }
241 :
242 : static void zend_mm_mem_win32_dtor(zend_mm_storage *storage)
243 : {
244 : HeapDestroy((HANDLE)storage->data);
245 : free(storage);
246 : }
247 :
248 : static zend_mm_segment* zend_mm_mem_win32_alloc(zend_mm_storage *storage, size_t size)
249 : {
250 : return (zend_mm_segment*) HeapAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, size);
251 : }
252 :
253 : static void zend_mm_mem_win32_free(zend_mm_storage *storage, zend_mm_segment* segment)
254 : {
255 : HeapFree((HANDLE)storage->data, HEAP_NO_SERIALIZE, segment);
256 : }
257 :
258 : static zend_mm_segment* zend_mm_mem_win32_realloc(zend_mm_storage *storage, zend_mm_segment* segment, size_t size)
259 : {
260 : return (zend_mm_segment*) HeapReAlloc((HANDLE)storage->data, HEAP_NO_SERIALIZE, segment, size);
261 : }
262 :
263 : # define ZEND_MM_MEM_WIN32_DSC {"win32", zend_mm_mem_win32_init, zend_mm_mem_win32_dtor, zend_mm_mem_win32_alloc, zend_mm_mem_win32_realloc, zend_mm_mem_win32_free}
264 :
265 : #endif
266 :
267 : #ifdef HAVE_MEM_MALLOC
268 :
269 : static zend_mm_segment* zend_mm_mem_malloc_alloc(zend_mm_storage *storage, size_t size)
270 43755 : {
271 43755 : return (zend_mm_segment*)malloc(size);
272 : }
273 :
274 : static zend_mm_segment* zend_mm_mem_malloc_realloc(zend_mm_storage *storage, zend_mm_segment *ptr, size_t size)
275 0 : {
276 0 : return (zend_mm_segment*)realloc(ptr, size);
277 : }
278 :
279 : static void zend_mm_mem_malloc_free(zend_mm_storage *storage, zend_mm_segment *ptr)
280 43787 : {
281 43787 : free(ptr);
282 43787 : }
283 :
284 : # define ZEND_MM_MEM_MALLOC_DSC {"malloc", zend_mm_mem_dummy_init, zend_mm_mem_dummy_dtor, zend_mm_mem_malloc_alloc, zend_mm_mem_malloc_realloc, zend_mm_mem_malloc_free}
285 :
286 : #endif
287 :
288 : static const zend_mm_mem_handlers mem_handlers[] = {
289 : #ifdef HAVE_MEM_WIN32
290 : ZEND_MM_MEM_WIN32_DSC,
291 : #endif
292 : #ifdef HAVE_MEM_MALLOC
293 : ZEND_MM_MEM_MALLOC_DSC,
294 : #endif
295 : #ifdef HAVE_MEM_MMAP_ANON
296 : ZEND_MM_MEM_MMAP_ANON_DSC,
297 : #endif
298 : #ifdef HAVE_MEM_MMAP_ZERO
299 : ZEND_MM_MEM_MMAP_ZERO_DSC,
300 : #endif
301 : {NULL, NULL, NULL, NULL, NULL, NULL}
302 : };
303 :
304 : # define ZEND_MM_STORAGE_DTOR() heap->storage->handlers->dtor(heap->storage)
305 : # define ZEND_MM_STORAGE_ALLOC(size) heap->storage->handlers->_alloc(heap->storage, size)
306 : # define ZEND_MM_STORAGE_REALLOC(ptr, size) heap->storage->handlers->_realloc(heap->storage, ptr, size)
307 : # define ZEND_MM_STORAGE_FREE(ptr) heap->storage->handlers->_free(heap->storage, ptr)
308 :
309 : /****************/
310 : /* Heap Manager */
311 : /****************/
312 :
313 : #define MEM_BLOCK_VALID 0x7312F8DC
314 : #define MEM_BLOCK_FREED 0x99954317
315 : #define MEM_BLOCK_CACHED 0xFB8277DC
316 : #define MEM_BLOCK_GUARD 0x2A8FCC84
317 : #define MEM_BLOCK_LEAK 0x6C5E8F2D
318 :
319 : /* mm block type */
320 : typedef struct _zend_mm_block_info {
321 : #if ZEND_MM_COOKIES
322 : size_t _cookie;
323 : #endif
324 : size_t _size;
325 : size_t _prev;
326 : } zend_mm_block_info;
327 :
328 : #if ZEND_DEBUG
329 :
330 : typedef struct _zend_mm_debug_info {
331 : char *filename;
332 : uint lineno;
333 : char *orig_filename;
334 : uint orig_lineno;
335 : size_t size;
336 : #if ZEND_MM_HEAP_PROTECTION
337 : unsigned int start_magic;
338 : #endif
339 : } zend_mm_debug_info;
340 :
341 : #elif ZEND_MM_HEAP_PROTECTION
342 :
343 : typedef struct _zend_mm_debug_info {
344 : size_t size;
345 : unsigned int start_magic;
346 : } zend_mm_debug_info;
347 :
348 : #endif
349 :
350 : typedef struct _zend_mm_block {
351 : zend_mm_block_info info;
352 : #if ZEND_DEBUG
353 : unsigned int magic;
354 : # ifdef ZTS
355 : THREAD_T thread_id;
356 : # endif
357 : zend_mm_debug_info debug;
358 : #elif ZEND_MM_HEAP_PROTECTION
359 : zend_mm_debug_info debug;
360 : #endif
361 : } zend_mm_block;
362 :
363 : typedef struct _zend_mm_small_free_block {
364 : zend_mm_block_info info;
365 : #if ZEND_DEBUG
366 : unsigned int magic;
367 : # ifdef ZTS
368 : THREAD_T thread_id;
369 : # endif
370 : #endif
371 : struct _zend_mm_free_block *prev_free_block;
372 : struct _zend_mm_free_block *next_free_block;
373 : } zend_mm_small_free_block;
374 :
375 : typedef struct _zend_mm_free_block {
376 : zend_mm_block_info info;
377 : #if ZEND_DEBUG
378 : unsigned int magic;
379 : # ifdef ZTS
380 : THREAD_T thread_id;
381 : # endif
382 : #endif
383 : struct _zend_mm_free_block *prev_free_block;
384 : struct _zend_mm_free_block *next_free_block;
385 :
386 : struct _zend_mm_free_block **parent;
387 : struct _zend_mm_free_block *child[2];
388 : } zend_mm_free_block;
389 :
390 : #define ZEND_MM_NUM_BUCKETS (sizeof(size_t) << 3)
391 :
392 : #define ZEND_MM_CACHE 1
393 : #define ZEND_MM_CACHE_SIZE (ZEND_MM_NUM_BUCKETS * 2 * 1024)
394 :
395 : #ifndef ZEND_MM_CACHE_STAT
396 : # define ZEND_MM_CACHE_STAT 0
397 : #endif
398 :
399 : struct _zend_mm_heap {
400 : int use_zend_alloc;
401 : size_t free_bitmap;
402 : size_t large_free_bitmap;
403 : size_t block_size;
404 : size_t compact_size;
405 : zend_mm_segment *segments_list;
406 : zend_mm_storage *storage;
407 : size_t real_size;
408 : size_t real_peak;
409 : size_t limit;
410 : size_t size;
411 : size_t peak;
412 : size_t reserve_size;
413 : void *reserve;
414 : int overflow;
415 : int internal;
416 : #if ZEND_MM_CACHE
417 : unsigned int cached;
418 : zend_mm_free_block *cache[ZEND_MM_NUM_BUCKETS];
419 : #endif
420 : zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];
421 : zend_mm_free_block *large_free_buckets[ZEND_MM_NUM_BUCKETS];
422 : zend_mm_free_block *rest_buckets[2];
423 : #if ZEND_MM_CACHE_STAT
424 : struct {
425 : int count;
426 : int max_count;
427 : int hit;
428 : int miss;
429 : } cache_stat[ZEND_MM_NUM_BUCKETS+1];
430 : #endif
431 : };
432 :
433 : #define ZEND_MM_SMALL_FREE_BUCKET(heap, index) \
434 : (zend_mm_free_block*) ((char*)&heap->free_buckets[index * 2] + \
435 : sizeof(zend_mm_free_block*) * 2 - \
436 : sizeof(zend_mm_small_free_block))
437 :
438 : #define ZEND_MM_REST_BUCKET(heap) \
439 : (zend_mm_free_block*)((char*)&heap->rest_buckets[0] + \
440 : sizeof(zend_mm_free_block*) * 2 - \
441 : sizeof(zend_mm_small_free_block))
442 :
443 : #if ZEND_MM_COOKIES
444 :
445 : static unsigned int _zend_mm_cookie = 0;
446 :
447 : # define ZEND_MM_COOKIE(block) \
448 : (((size_t)(block)) ^ _zend_mm_cookie)
449 : # define ZEND_MM_SET_COOKIE(block) \
450 : (block)->info._cookie = ZEND_MM_COOKIE(block)
451 : # define ZEND_MM_CHECK_COOKIE(block) \
452 : if (UNEXPECTED((block)->info._cookie != ZEND_MM_COOKIE(block))) { \
453 : zend_mm_panic("zend_mm_heap corrupted"); \
454 : }
455 : #else
456 : # define ZEND_MM_SET_COOKIE(block)
457 : # define ZEND_MM_CHECK_COOKIE(block)
458 : #endif
459 :
460 : /* Default memory segment size */
461 : #define ZEND_MM_SEG_SIZE (256 * 1024)
462 :
463 : /* Reserved space for error reporting in case of memory overflow */
464 : #define ZEND_MM_RESERVE_SIZE (8*1024)
465 :
466 : #ifdef _WIN64
467 : # define ZEND_MM_LONG_CONST(x) (x##i64)
468 : #else
469 : # define ZEND_MM_LONG_CONST(x) (x##L)
470 : #endif
471 :
472 : #define ZEND_MM_TYPE_MASK ZEND_MM_LONG_CONST(0x3)
473 :
474 : #define ZEND_MM_FREE_BLOCK ZEND_MM_LONG_CONST(0x0)
475 : #define ZEND_MM_USED_BLOCK ZEND_MM_LONG_CONST(0x1)
476 : #define ZEND_MM_GUARD_BLOCK ZEND_MM_LONG_CONST(0x3)
477 :
478 : #define ZEND_MM_BLOCK(b, type, size) do { \
479 : size_t _size = (size); \
480 : (b)->info._size = (type) | _size; \
481 : ZEND_MM_BLOCK_AT(b, _size)->info._prev = (type) | _size; \
482 : ZEND_MM_SET_COOKIE(b); \
483 : } while (0);
484 : #define ZEND_MM_LAST_BLOCK(b) do { \
485 : (b)->info._size = ZEND_MM_GUARD_BLOCK | ZEND_MM_ALIGNED_HEADER_SIZE; \
486 : ZEND_MM_SET_MAGIC(b, MEM_BLOCK_GUARD); \
487 : } while (0);
488 : #define ZEND_MM_BLOCK_SIZE(b) ((b)->info._size & ~ZEND_MM_TYPE_MASK)
489 : #define ZEND_MM_IS_FREE_BLOCK(b) (!((b)->info._size & ZEND_MM_USED_BLOCK))
490 : #define ZEND_MM_IS_USED_BLOCK(b) ((b)->info._size & ZEND_MM_USED_BLOCK)
491 : #define ZEND_MM_IS_GUARD_BLOCK(b) (((b)->info._size & ZEND_MM_TYPE_MASK) == ZEND_MM_GUARD_BLOCK)
492 :
493 : #define ZEND_MM_NEXT_BLOCK(b) ZEND_MM_BLOCK_AT(b, ZEND_MM_BLOCK_SIZE(b))
494 : #define ZEND_MM_PREV_BLOCK(b) ZEND_MM_BLOCK_AT(b, -(int)((b)->info._prev & ~ZEND_MM_TYPE_MASK))
495 :
496 : #define ZEND_MM_PREV_BLOCK_IS_FREE(b) (!((b)->info._prev & ZEND_MM_USED_BLOCK))
497 :
498 : #define ZEND_MM_MARK_FIRST_BLOCK(b) ((b)->info._prev = ZEND_MM_GUARD_BLOCK)
499 : #define ZEND_MM_IS_FIRST_BLOCK(b) ((b)->info._prev == ZEND_MM_GUARD_BLOCK)
500 :
501 : /* optimized access */
502 : #define ZEND_MM_FREE_BLOCK_SIZE(b) (b)->info._size
503 :
504 : #ifndef ZEND_MM_ALIGNMENT
505 : # define ZEND_MM_ALIGNMENT 8
506 : # define ZEND_MM_ALIGNMENT_LOG2 3
507 : #elif ZEND_MM_ALIGNMENT < 4
508 : # undef ZEND_MM_ALIGNMENT
509 : # undef ZEND_MM_ALIGNMENT_LOG2
510 : # define ZEND_MM_ALIGNMENT 4
511 : # define ZEND_MM_ALIGNMENT_LOG2 2
512 : #endif
513 :
514 : #define ZEND_MM_ALIGNMENT_MASK ~(ZEND_MM_ALIGNMENT-1)
515 :
516 : /* Aligned header size */
517 : #define ZEND_MM_ALIGNED_SIZE(size) ((size + ZEND_MM_ALIGNMENT - 1) & ZEND_MM_ALIGNMENT_MASK)
518 : #define ZEND_MM_ALIGNED_HEADER_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_block))
519 : #define ZEND_MM_ALIGNED_FREE_HEADER_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_small_free_block))
520 : #define ZEND_MM_MIN_ALLOC_BLOCK_SIZE ZEND_MM_ALIGNED_SIZE(ZEND_MM_ALIGNED_HEADER_SIZE + END_MAGIC_SIZE)
521 : #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)
522 : #define ZEND_MM_ALIGNED_SEGMENT_SIZE ZEND_MM_ALIGNED_SIZE(sizeof(zend_mm_segment))
523 :
524 : #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)
525 :
526 : #define ZEND_MM_MAX_SMALL_SIZE ((ZEND_MM_NUM_BUCKETS<<ZEND_MM_ALIGNMENT_LOG2)+ZEND_MM_ALIGNED_MIN_HEADER_SIZE)
527 :
528 : #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)))
529 :
530 : #define ZEND_MM_BUCKET_INDEX(true_size) ((true_size>>ZEND_MM_ALIGNMENT_LOG2)-(ZEND_MM_ALIGNED_MIN_HEADER_SIZE>>ZEND_MM_ALIGNMENT_LOG2))
531 :
532 : #define ZEND_MM_SMALL_SIZE(true_size) (true_size < ZEND_MM_MAX_SMALL_SIZE)
533 :
534 : /* Memory calculations */
535 : #define ZEND_MM_BLOCK_AT(blk, offset) ((zend_mm_block *) (((char *) (blk))+(offset)))
536 : #define ZEND_MM_DATA_OF(p) ((void *) (((char *) (p))+ZEND_MM_ALIGNED_HEADER_SIZE))
537 : #define ZEND_MM_HEADER_OF(blk) ZEND_MM_BLOCK_AT(blk, -(int)ZEND_MM_ALIGNED_HEADER_SIZE)
538 :
539 : /* Debug output */
540 : #if ZEND_DEBUG
541 :
542 : # ifdef ZTS
543 : # define ZEND_MM_SET_THREAD_ID(block) \
544 : ((zend_mm_block*)(block))->thread_id = tsrm_thread_id()
545 : # define ZEND_MM_BAD_THREAD_ID(block) ((block)->thread_id != tsrm_thread_id())
546 : # else
547 : # define ZEND_MM_SET_THREAD_ID(block)
548 : # define ZEND_MM_BAD_THREAD_ID(block) 0
549 : # endif
550 :
551 : # define ZEND_MM_VALID_PTR(block) \
552 : zend_mm_check_ptr(heap, block, 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC)
553 :
554 : # define ZEND_MM_SET_MAGIC(block, val) do { \
555 : (block)->magic = (val); \
556 : } while (0)
557 :
558 : # define ZEND_MM_CHECK_MAGIC(block, val) do { \
559 : if ((block)->magic != (val)) { \
560 : zend_mm_panic("zend_mm_heap corrupted"); \
561 : } \
562 : } while (0)
563 :
564 : # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) do { \
565 : ((zend_mm_block*)(block))->debug.filename = __zend_filename; \
566 : ((zend_mm_block*)(block))->debug.lineno = __zend_lineno; \
567 : ((zend_mm_block*)(block))->debug.orig_filename = __zend_orig_filename; \
568 : ((zend_mm_block*)(block))->debug.orig_lineno = __zend_orig_lineno; \
569 : ZEND_MM_SET_BLOCK_SIZE(block, __size); \
570 : if (set_valid) { \
571 : ZEND_MM_SET_MAGIC(block, MEM_BLOCK_VALID); \
572 : } \
573 : if (set_thread) { \
574 : ZEND_MM_SET_THREAD_ID(block); \
575 : } \
576 : } while (0)
577 :
578 : #else
579 :
580 : # define ZEND_MM_VALID_PTR(ptr) EXPECTED(ptr != NULL)
581 :
582 : # define ZEND_MM_SET_MAGIC(block, val)
583 :
584 : # define ZEND_MM_CHECK_MAGIC(block, val)
585 :
586 : # define ZEND_MM_SET_DEBUG_INFO(block, __size, set_valid, set_thread) ZEND_MM_SET_BLOCK_SIZE(block, __size)
587 :
588 : #endif
589 :
590 :
591 : #if ZEND_MM_HEAP_PROTECTION
592 :
593 : # define ZEND_MM_CHECK_PROTECTION(block) \
594 : do { \
595 : if ((block)->debug.start_magic != _mem_block_start_magic || \
596 : memcmp(ZEND_MM_END_MAGIC_PTR(block), &_mem_block_end_magic, END_MAGIC_SIZE) != 0) { \
597 : zend_mm_panic("zend_mm_heap corrupted"); \
598 : } \
599 : } while (0)
600 :
601 : # define ZEND_MM_END_MAGIC_PTR(block) \
602 : (((char*)(ZEND_MM_DATA_OF(block))) + ((zend_mm_block*)(block))->debug.size)
603 :
604 : # define END_MAGIC_SIZE sizeof(unsigned int)
605 :
606 : # define ZEND_MM_SET_BLOCK_SIZE(block, __size) do { \
607 : char *p; \
608 : ((zend_mm_block*)(block))->debug.size = (__size); \
609 : p = ZEND_MM_END_MAGIC_PTR(block); \
610 : ((zend_mm_block*)(block))->debug.start_magic = _mem_block_start_magic; \
611 : memcpy(p, &_mem_block_end_magic, END_MAGIC_SIZE); \
612 : } while (0)
613 :
614 : static unsigned int _mem_block_start_magic = 0;
615 : static unsigned int _mem_block_end_magic = 0;
616 :
617 : #else
618 :
619 : # if ZEND_DEBUG
620 : # define ZEND_MM_SET_BLOCK_SIZE(block, _size) \
621 : ((zend_mm_block*)(block))->debug.size = (_size)
622 : # else
623 : # define ZEND_MM_SET_BLOCK_SIZE(block, _size)
624 : # endif
625 :
626 : # define ZEND_MM_CHECK_PROTECTION(block)
627 :
628 : # define END_MAGIC_SIZE 0
629 :
630 : #endif
631 :
632 : #if ZEND_MM_SAFE_UNLINKING
633 : # define ZEND_MM_CHECK_BLOCK_LINKAGE(block) \
634 : if (UNEXPECTED((block)->info._size != ZEND_MM_BLOCK_AT(block, ZEND_MM_FREE_BLOCK_SIZE(block))->info._prev) || \
635 : UNEXPECTED(!UNEXPECTED(ZEND_MM_IS_FIRST_BLOCK(block)) && \
636 : UNEXPECTED(ZEND_MM_PREV_BLOCK(block)->info._size != (block)->info._prev))) { \
637 : zend_mm_panic("zend_mm_heap corrupted"); \
638 : }
639 : #define ZEND_MM_CHECK_TREE(block) \
640 : if (UNEXPECTED(*((block)->parent) != (block))) { \
641 : zend_mm_panic("zend_mm_heap corrupted"); \
642 : }
643 : #else
644 : # define ZEND_MM_CHECK_BLOCK_LINKAGE(block)
645 : # define ZEND_MM_CHECK_TREE(block)
646 : #endif
647 :
648 : #define ZEND_MM_LARGE_BUCKET_INDEX(S) zend_mm_high_bit(S)
649 :
650 : 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;
651 : static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
652 : static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
653 :
654 : static inline unsigned int zend_mm_high_bit(size_t _size)
655 21185923 : {
656 : #if defined(__GNUC__) && defined(i386)
657 : unsigned int n;
658 :
659 21185923 : __asm__("bsrl %1,%0\n\t" : "=r" (n) : "rm" (_size));
660 21185923 : return n;
661 : #elif defined(__GNUC__) && defined(__x86_64__)
662 : unsigned long n;
663 :
664 : __asm__("bsrq %1,%0\n\t" : "=r" (n) : "rm" (_size));
665 : return (unsigned int)n;
666 : #elif defined(_MSC_VER) && defined(_M_IX86)
667 : __asm {
668 : bsr eax, _size
669 : }
670 : #else
671 : unsigned int n = 0;
672 : while (_size != 0) {
673 : _size = _size >> 1;
674 : n++;
675 : }
676 : return n-1;
677 : #endif
678 : }
679 :
680 : static inline unsigned int zend_mm_low_bit(size_t _size)
681 22572909 : {
682 : #if defined(__GNUC__) && defined(i386)
683 : unsigned int n;
684 :
685 22572909 : __asm__("bsfl %1,%0\n\t" : "=r" (n) : "rm" (_size));
686 22572909 : return n;
687 : #elif defined(__GNUC__) && defined(__x86_64__)
688 : unsigned long n;
689 :
690 : __asm__("bsfq %1,%0\n\t" : "=r" (n) : "rm" (_size));
691 : return (unsigned int)n;
692 : #elif defined(_MSC_VER) && defined(_M_IX86)
693 : __asm {
694 : bsf eax, _size
695 : }
696 : #else
697 : static const int offset[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
698 : unsigned int n;
699 : unsigned int index = 0;
700 :
701 : do {
702 : n = offset[_size & 15];
703 : _size >>= 4;
704 : index += n;
705 : } while (n == 4);
706 : return index;
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 10264 : {
712 : zend_mm_free_block *prev, *next;
713 :
714 : ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
715 :
716 10264 : if (!ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block))) {
717 10264 : mm_block->parent = NULL;
718 : }
719 :
720 10264 : prev = heap->rest_buckets[0];
721 10264 : next = prev->next_free_block;
722 10264 : mm_block->prev_free_block = prev;
723 10264 : mm_block->next_free_block = next;
724 10264 : prev->next_free_block = next->prev_free_block = mm_block;
725 10264 : }
726 :
727 : static inline void zend_mm_add_to_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
728 32836952 : {
729 : size_t size;
730 : size_t index;
731 :
732 : ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_FREED);
733 :
734 32836952 : size = ZEND_MM_FREE_BLOCK_SIZE(mm_block);
735 32836952 : if (EXPECTED(!ZEND_MM_SMALL_SIZE(size))) {
736 : zend_mm_free_block **p;
737 :
738 8888326 : index = ZEND_MM_LARGE_BUCKET_INDEX(size);
739 8888326 : p = &heap->large_free_buckets[index];
740 8888326 : mm_block->child[0] = mm_block->child[1] = NULL;
741 8888326 : if (!*p) {
742 5563167 : *p = mm_block;
743 5563167 : mm_block->parent = p;
744 5563167 : mm_block->prev_free_block = mm_block->next_free_block = mm_block;
745 5563167 : heap->large_free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
746 : } else {
747 : size_t m;
748 :
749 5769088 : for (m = size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
750 5769088 : zend_mm_free_block *prev = *p;
751 :
752 5769088 : if (ZEND_MM_FREE_BLOCK_SIZE(prev) != size) {
753 5456432 : p = &prev->child[(m >> (ZEND_MM_NUM_BUCKETS-1)) & 1];
754 5456432 : if (!*p) {
755 3012503 : *p = mm_block;
756 3012503 : mm_block->parent = p;
757 3012503 : mm_block->prev_free_block = mm_block->next_free_block = mm_block;
758 3012503 : break;
759 : }
760 : } else {
761 312656 : zend_mm_free_block *next = prev->next_free_block;
762 :
763 312656 : prev->next_free_block = next->prev_free_block = mm_block;
764 312656 : mm_block->next_free_block = next;
765 312656 : mm_block->prev_free_block = prev;
766 312656 : mm_block->parent = NULL;
767 312656 : break;
768 : }
769 2443929 : }
770 : }
771 : } else {
772 : zend_mm_free_block *prev, *next;
773 :
774 23948626 : index = ZEND_MM_BUCKET_INDEX(size);
775 :
776 23948626 : prev = ZEND_MM_SMALL_FREE_BUCKET(heap, index);
777 23948626 : if (prev->prev_free_block == prev) {
778 10193891 : heap->free_bitmap |= (ZEND_MM_LONG_CONST(1) << index);
779 : }
780 23948626 : next = prev->next_free_block;
781 :
782 23948626 : mm_block->prev_free_block = prev;
783 23948626 : mm_block->next_free_block = next;
784 23948626 : prev->next_free_block = next->prev_free_block = mm_block;
785 : }
786 32836952 : }
787 :
788 : static inline void zend_mm_remove_from_free_list(zend_mm_heap *heap, zend_mm_free_block *mm_block)
789 32804574 : {
790 32804574 : zend_mm_free_block *prev = mm_block->prev_free_block;
791 32804574 : zend_mm_free_block *next = mm_block->next_free_block;
792 :
793 : ZEND_MM_CHECK_MAGIC(mm_block, MEM_BLOCK_FREED);
794 :
795 32804574 : if (EXPECTED(prev == mm_block)) {
796 : zend_mm_free_block **rp, **cp;
797 :
798 : #if ZEND_MM_SAFE_UNLINKING
799 8534364 : if (UNEXPECTED(next != mm_block)) {
800 0 : zend_mm_panic("zend_mm_heap corrupted");
801 : }
802 : #endif
803 :
804 8534364 : rp = &mm_block->child[mm_block->child[1] != NULL];
805 8534364 : prev = *rp;
806 8534364 : if (EXPECTED(prev == NULL)) {
807 7158889 : size_t index = ZEND_MM_LARGE_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
808 :
809 7158889 : ZEND_MM_CHECK_TREE(mm_block);
810 7158889 : *mm_block->parent = NULL;
811 7158889 : if (mm_block->parent == &heap->large_free_buckets[index]) {
812 5522422 : heap->large_free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
813 : }
814 : } else {
815 3531051 : while (*(cp = &(prev->child[prev->child[1] != NULL])) != NULL) {
816 780101 : prev = *cp;
817 780101 : rp = cp;
818 : }
819 1375475 : *rp = NULL;
820 :
821 1405200 : subst_block:
822 1405200 : ZEND_MM_CHECK_TREE(mm_block);
823 1405200 : *mm_block->parent = prev;
824 1405200 : prev->parent = mm_block->parent;
825 1405200 : if ((prev->child[0] = mm_block->child[0])) {
826 723974 : ZEND_MM_CHECK_TREE(prev->child[0]);
827 723974 : prev->child[0]->parent = &prev->child[0];
828 : }
829 1405200 : if ((prev->child[1] = mm_block->child[1])) {
830 102745 : ZEND_MM_CHECK_TREE(prev->child[1]);
831 102745 : prev->child[1]->parent = &prev->child[1];
832 : }
833 : }
834 : } else {
835 :
836 : #if ZEND_MM_SAFE_UNLINKING
837 24270210 : 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 24270210 : prev->next_free_block = next;
843 24270210 : next->prev_free_block = prev;
844 :
845 24270210 : if (EXPECTED(ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block)))) {
846 23948243 : if (EXPECTED(prev == next)) {
847 10193859 : size_t index = ZEND_MM_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));
848 :
849 10193859 : if (EXPECTED(heap->free_buckets[index*2] == heap->free_buckets[index*2+1])) {
850 10193859 : heap->free_bitmap &= ~(ZEND_MM_LONG_CONST(1) << index);
851 : }
852 : }
853 321967 : } else if (UNEXPECTED(mm_block->parent != NULL)) {
854 29725 : goto subst_block;
855 : }
856 : }
857 32804574 : }
858 :
859 : static inline void zend_mm_init(zend_mm_heap *heap)
860 40714 : {
861 : zend_mm_free_block* p;
862 : int i;
863 :
864 40714 : heap->free_bitmap = 0;
865 40714 : heap->large_free_bitmap = 0;
866 : #if ZEND_MM_CACHE
867 40714 : heap->cached = 0;
868 40714 : 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 40714 : p = ZEND_MM_SMALL_FREE_BUCKET(heap, 0);
876 1343562 : for (i = 0; i < ZEND_MM_NUM_BUCKETS; i++) {
877 1302848 : p->next_free_block = p;
878 1302848 : p->prev_free_block = p;
879 1302848 : p = (zend_mm_free_block*)((char*)p + sizeof(zend_mm_free_block*) * 2);
880 1302848 : heap->large_free_buckets[i] = NULL;
881 : }
882 40714 : heap->rest_buckets[0] = heap->rest_buckets[1] = ZEND_MM_REST_BUCKET(heap);
883 40714 : }
884 :
885 : static void zend_mm_del_segment(zend_mm_heap *heap, zend_mm_segment *segment)
886 3029 : {
887 3029 : zend_mm_segment **p = &heap->segments_list;
888 :
889 6157 : while (*p != segment) {
890 99 : p = &(*p)->next_segment;
891 : }
892 3029 : *p = segment->next_segment;
893 3029 : heap->real_size -= segment->size;
894 3029 : ZEND_MM_STORAGE_FREE(segment);
895 3029 : }
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 13565 : {
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 13565 : 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 13565 : storage = handlers->init(params);
1037 13565 : if (!storage) {
1038 0 : fprintf(stderr, "Cannot initialize zend_mm storage [%s]\n", handlers->name);
1039 0 : exit(255);
1040 : }
1041 13565 : storage->handlers = handlers;
1042 :
1043 13565 : heap = malloc(sizeof(struct _zend_mm_heap));
1044 :
1045 13565 : heap->storage = storage;
1046 13565 : heap->block_size = block_size;
1047 13565 : heap->compact_size = 0;
1048 13565 : heap->segments_list = NULL;
1049 13565 : zend_mm_init(heap);
1050 : # if ZEND_MM_CACHE_STAT
1051 : memset(heap->cache_stat, 0, sizeof(heap->cache_stat));
1052 : # endif
1053 :
1054 13565 : heap->use_zend_alloc = 1;
1055 13565 : heap->real_size = 0;
1056 13565 : heap->overflow = 0;
1057 13565 : heap->real_peak = 0;
1058 13565 : heap->limit = ZEND_MM_LONG_CONST(1)<<(ZEND_MM_NUM_BUCKETS-2);
1059 13565 : heap->size = 0;
1060 13565 : heap->peak = 0;
1061 13565 : heap->internal = internal;
1062 13565 : heap->reserve = NULL;
1063 13565 : heap->reserve_size = reserve_size;
1064 13565 : if (reserve_size > 0) {
1065 13565 : heap->reserve = _zend_mm_alloc_int(heap, reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
1066 : }
1067 13565 : 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 13565 : return heap;
1099 : }
1100 :
1101 : ZEND_API zend_mm_heap *zend_mm_startup(void)
1102 13565 : {
1103 : int i;
1104 : size_t seg_size;
1105 13565 : 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 13565 : if (mem_type == NULL) {
1111 13565 : 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 13565 : handlers = &mem_handlers[i];
1128 :
1129 13565 : tmp = getenv("ZEND_MM_SEG_SIZE");
1130 13565 : 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 13565 : seg_size = ZEND_MM_SEG_SIZE;
1141 : }
1142 :
1143 13565 : heap = zend_mm_startup_ex(handlers, seg_size, ZEND_MM_RESERVE_SIZE, 0, NULL);
1144 13565 : if (heap) {
1145 13565 : tmp = getenv("ZEND_MM_COMPACT");
1146 13565 : if (tmp) {
1147 0 : heap->compact_size = zend_atoi(tmp, 0);
1148 : } else {
1149 13565 : heap->compact_size = 2 * 1024 * 1024;
1150 : }
1151 : }
1152 13565 : 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)
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);
1229 : zend_message_dispatcher(ZMSG_MEMORY_LEAK_DETECTED, &leak);
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);
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);
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 : zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL);
1273 : zend_debug_alloc_output("---------------------------------------\n");
1274 : zend_debug_alloc_output("%s(%d) : Block "PTR_FMT" status:\n" ZEND_FILE_LINE_RELAY_CC, ptr);
1275 : if (__zend_orig_filename) {
1276 : zend_debug_alloc_output("%s(%d) : Actual location (location was relayed)\n" ZEND_FILE_LINE_ORIG_RELAY_CC);
1277 : }
1278 : if (!ptr) {
1279 : zend_debug_alloc_output("NULL\n");
1280 : zend_debug_alloc_output("---------------------------------------\n");
1281 : return 0;
1282 : }
1283 : }
1284 :
1285 : if (!ptr) {
1286 : if (silent) {
1287 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1288 : }
1289 : }
1290 :
1291 : p = ZEND_MM_HEADER_OF(ptr);
1292 :
1293 : #ifdef ZTS
1294 : if (ZEND_MM_BAD_THREAD_ID(p)) {
1295 : if (!silent) {
1296 : zend_debug_alloc_output("Invalid pointer: ((thread_id=0x%0.8X) != (expected=0x%0.8X))\n", (long)p->thread_id, (long)tsrm_thread_id());
1297 : had_problems = 1;
1298 : } else {
1299 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1300 : }
1301 : }
1302 : #endif
1303 :
1304 : if (p->info._size != ZEND_MM_NEXT_BLOCK(p)->info._prev) {
1305 : if (!silent) {
1306 : zend_debug_alloc_output("Invalid pointer: ((size="PTR_FMT") != (next.prev="PTR_FMT"))\n", p->info._size, ZEND_MM_NEXT_BLOCK(p)->info._prev);
1307 : had_problems = 1;
1308 : } else {
1309 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1310 : }
1311 : }
1312 : if (p->info._prev != ZEND_MM_GUARD_BLOCK &&
1313 : ZEND_MM_PREV_BLOCK(p)->info._size != p->info._prev) {
1314 : if (!silent) {
1315 : zend_debug_alloc_output("Invalid pointer: ((prev="PTR_FMT") != (prev.size="PTR_FMT"))\n", p->info._prev, ZEND_MM_PREV_BLOCK(p)->info._size);
1316 : had_problems = 1;
1317 : } else {
1318 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1319 : }
1320 : }
1321 :
1322 : if (had_problems) {
1323 : zend_debug_alloc_output("---------------------------------------\n");
1324 : return 0;
1325 : }
1326 :
1327 : if (!silent) {
1328 : zend_debug_alloc_output("%10s\t","Beginning: ");
1329 : }
1330 :
1331 : if (!ZEND_MM_IS_USED_BLOCK(p)) {
1332 : if (!silent) {
1333 : if (p->magic != MEM_BLOCK_FREED) {
1334 : zend_debug_alloc_output("Freed (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
1335 : } else {
1336 : zend_debug_alloc_output("Freed\n");
1337 : }
1338 : had_problems = 1;
1339 : } else {
1340 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1341 : }
1342 : } else if (ZEND_MM_IS_GUARD_BLOCK(p)) {
1343 : if (!silent) {
1344 : if (p->magic != MEM_BLOCK_FREED) {
1345 : zend_debug_alloc_output("Guard (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_FREED);
1346 : } else {
1347 : zend_debug_alloc_output("Guard\n");
1348 : }
1349 : had_problems = 1;
1350 : } else {
1351 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1352 : }
1353 : } else {
1354 : switch (p->magic) {
1355 : case MEM_BLOCK_VALID:
1356 : case MEM_BLOCK_LEAK:
1357 : if (!silent) {
1358 : zend_debug_alloc_output("OK (allocated on %s:%d, %d bytes)\n", p->debug.filename, p->debug.lineno, (int)p->debug.size);
1359 : }
1360 : break; /* ok */
1361 : case MEM_BLOCK_CACHED:
1362 : if (!no_cache_notice) {
1363 : if (!silent) {
1364 : zend_debug_alloc_output("Cached\n");
1365 : had_problems = 1;
1366 : } else {
1367 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1368 : }
1369 : }
1370 : case MEM_BLOCK_FREED:
1371 : if (!silent) {
1372 : zend_debug_alloc_output("Freed (invalid)\n");
1373 : had_problems = 1;
1374 : } else {
1375 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1376 : }
1377 : break;
1378 : case MEM_BLOCK_GUARD:
1379 : if (!silent) {
1380 : zend_debug_alloc_output("Guard (invalid)\n");
1381 : had_problems = 1;
1382 : } else {
1383 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1384 : }
1385 : break;
1386 : default:
1387 : if (!silent) {
1388 : zend_debug_alloc_output("Unknown (magic=0x%0.8X, expected=0x%0.8X)\n", p->magic, MEM_BLOCK_VALID);
1389 : had_problems = 1;
1390 : valid_beginning = 0;
1391 : } else {
1392 : return zend_mm_check_ptr(heap, ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1393 : }
1394 : break;
1395 : }
1396 : }
1397 :
1398 : #if ZEND_MM_HEAP_PROTECTION
1399 : if (!valid_beginning) {
1400 : if (!silent) {
1401 : zend_debug_alloc_output("%10s\t", "Start:");
1402 : zend_debug_alloc_output("Unknown\n");
1403 : zend_debug_alloc_output("%10s\t", "End:");
1404 : zend_debug_alloc_output("Unknown\n");
1405 : }
1406 : } else {
1407 : char *end_magic = ZEND_MM_END_MAGIC_PTR(p);
1408 :
1409 : if (p->debug.start_magic == _mem_block_start_magic) {
1410 : if (!silent) {
1411 : zend_debug_alloc_output("%10s\t", "Start:");
1412 : zend_debug_alloc_output("OK\n");
1413 : }
1414 : } else {
1415 : char *overflow_ptr, *magic_ptr=(char *) &_mem_block_start_magic;
1416 : int overflows=0;
1417 : int i;
1418 :
1419 : if (silent) {
1420 : return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1421 : }
1422 : had_problems = 1;
1423 : overflow_ptr = (char *) &p->debug.start_magic;
1424 : i = END_MAGIC_SIZE;
1425 : while (--i >= 0) {
1426 : if (overflow_ptr[i]!=magic_ptr[i]) {
1427 : overflows++;
1428 : }
1429 : }
1430 : zend_debug_alloc_output("%10s\t", "Start:");
1431 : zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", p->debug.start_magic, _mem_block_start_magic);
1432 : zend_debug_alloc_output("%10s\t","");
1433 : if (overflows >= END_MAGIC_SIZE) {
1434 : zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
1435 : } else {
1436 : zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
1437 : }
1438 : }
1439 : if (memcmp(end_magic, &_mem_block_end_magic, END_MAGIC_SIZE)==0) {
1440 : if (!silent) {
1441 : zend_debug_alloc_output("%10s\t", "End:");
1442 : zend_debug_alloc_output("OK\n");
1443 : }
1444 : } else {
1445 : char *overflow_ptr, *magic_ptr=(char *) &_mem_block_end_magic;
1446 : int overflows=0;
1447 : int i;
1448 :
1449 : if (silent) {
1450 : return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1451 : }
1452 : had_problems = 1;
1453 : overflow_ptr = (char *) end_magic;
1454 :
1455 : for (i=0; i < END_MAGIC_SIZE; i++) {
1456 : if (overflow_ptr[i]!=magic_ptr[i]) {
1457 : overflows++;
1458 : }
1459 : }
1460 :
1461 : zend_debug_alloc_output("%10s\t", "End:");
1462 : zend_debug_alloc_output("Overflown (magic=0x%0.8X instead of 0x%0.8X)\n", *end_magic, _mem_block_end_magic);
1463 : zend_debug_alloc_output("%10s\t","");
1464 : if (overflows >= END_MAGIC_SIZE) {
1465 : zend_debug_alloc_output("At least %d bytes overflown\n", END_MAGIC_SIZE);
1466 : } else {
1467 : zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
1468 : }
1469 : }
1470 : }
1471 : #endif
1472 :
1473 : if (!silent) {
1474 : zend_debug_alloc_output("---------------------------------------\n");
1475 : }
1476 : return ((!had_problems) ? 1 : 0);
1477 : }
1478 :
1479 : static int zend_mm_check_heap(zend_mm_heap *heap, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
1480 : {
1481 : zend_mm_segment *segment = heap->segments_list;
1482 : zend_mm_block *p, *q;
1483 : int errors = 0;
1484 :
1485 : if (!segment) {
1486 : return 0;
1487 : }
1488 : p = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
1489 : while (1) {
1490 : q = ZEND_MM_NEXT_BLOCK(p);
1491 : if (q <= p ||
1492 : (char*)q > (char*)segment + segment->size ||
1493 : p->info._size != q->info._prev) {
1494 : zend_mm_panic("zend_mm_heap corrupted");
1495 : }
1496 : if (!ZEND_MM_IS_FREE_BLOCK(p)) {
1497 : if (p->magic == MEM_BLOCK_VALID || p->magic == MEM_BLOCK_LEAK) {
1498 : 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)) {
1499 : errors++;
1500 : }
1501 : #if ZEND_MM_CACHE
1502 : } else if (p->magic == MEM_BLOCK_CACHED) {
1503 : /* skip it */
1504 : #endif
1505 : } else if (p->magic != MEM_BLOCK_LEAK) {
1506 : zend_mm_panic("zend_mm_heap corrupted");
1507 : }
1508 : }
1509 : if (ZEND_MM_IS_GUARD_BLOCK(q)) {
1510 : segment = segment->next_segment;
1511 : if (!segment) {
1512 : return errors;
1513 : }
1514 : q = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
1515 : }
1516 : p = q;
1517 : }
1518 : }
1519 : #endif
1520 :
1521 : ZEND_API void zend_mm_shutdown(zend_mm_heap *heap, int full_shutdown, int silent)
1522 40746 : {
1523 : zend_mm_storage *storage;
1524 : zend_mm_segment *segment;
1525 : zend_mm_segment *prev;
1526 : int internal;
1527 :
1528 40746 : if (heap->reserve) {
1529 : #if ZEND_DEBUG
1530 : if (!silent) {
1531 : _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
1532 : }
1533 : #endif
1534 40746 : heap->reserve = NULL;
1535 : }
1536 :
1537 : #if ZEND_MM_CACHE_STAT
1538 : if (full_shutdown) {
1539 : FILE *f;
1540 :
1541 : f = fopen("zend_mm.log", "w");
1542 : if (f) {
1543 : int i,j;
1544 : size_t size, true_size, min_size, max_size;
1545 : int hit = 0, miss = 0;
1546 :
1547 : fprintf(f, "\nidx min_size max_size true_size max_len hits misses\n");
1548 : size = 0;
1549 : while (1) {
1550 : true_size = ZEND_MM_TRUE_SIZE(size);
1551 : if (ZEND_MM_SMALL_SIZE(true_size)) {
1552 : min_size = size;
1553 : i = ZEND_MM_BUCKET_INDEX(true_size);
1554 : size++;
1555 : while (1) {
1556 : true_size = ZEND_MM_TRUE_SIZE(size);
1557 : if (ZEND_MM_SMALL_SIZE(true_size)) {
1558 : j = ZEND_MM_BUCKET_INDEX(true_size);
1559 : if (j > i) {
1560 : max_size = size-1;
1561 : break;
1562 : }
1563 : } else {
1564 : max_size = size-1;
1565 : break;
1566 : }
1567 : size++;
1568 : }
1569 : hit += heap->cache_stat[i].hit;
1570 : miss += heap->cache_stat[i].miss;
1571 : 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);
1572 : } else {
1573 : break;
1574 : }
1575 : }
1576 : fprintf(f, " %8d %8d\n", hit, miss);
1577 : fprintf(f, " %8d %8d\n", heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit, heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss);
1578 : fclose(f);
1579 : }
1580 : }
1581 : #endif
1582 :
1583 : #if ZEND_DEBUG
1584 : if (!silent) {
1585 : zend_mm_check_leaks(heap);
1586 : }
1587 : #endif
1588 :
1589 40746 : internal = heap->internal;
1590 40746 : storage = heap->storage;
1591 40746 : segment = heap->segments_list;
1592 122250 : while (segment) {
1593 40758 : prev = segment;
1594 40758 : segment = segment->next_segment;
1595 40758 : ZEND_MM_STORAGE_FREE(prev);
1596 : }
1597 40746 : if (full_shutdown) {
1598 13597 : storage->handlers->dtor(storage);
1599 13597 : if (!internal) {
1600 13597 : free(heap);
1601 : }
1602 : } else {
1603 : #ifdef HAVE_MEM_WIN32
1604 : /* FIX for bug #41713 */
1605 : /* TODO: add new "compact" handler */
1606 : if (heap->compact_size &&
1607 : heap->real_peak > heap->compact_size &&
1608 : storage->handlers->dtor == zend_mm_mem_win32_dtor &&
1609 : storage->handlers->init == zend_mm_mem_win32_init) {
1610 : HeapDestroy((HANDLE)storage->data);
1611 : storage->data = (void*)HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
1612 : }
1613 : #endif
1614 27149 : heap->segments_list = NULL;
1615 27149 : zend_mm_init(heap);
1616 27149 : heap->real_size = 0;
1617 27149 : heap->real_peak = 0;
1618 27149 : heap->size = 0;
1619 27149 : heap->peak = 0;
1620 27149 : if (heap->reserve_size) {
1621 27149 : heap->reserve = _zend_mm_alloc_int(heap, heap->reserve_size ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
1622 : }
1623 27149 : heap->overflow = 0;
1624 : }
1625 40746 : }
1626 :
1627 : static void zend_mm_safe_error(zend_mm_heap *heap,
1628 : const char *format,
1629 : size_t limit,
1630 : #if ZEND_DEBUG
1631 : const char *filename,
1632 : uint lineno,
1633 : #endif
1634 : size_t size)
1635 0 : {
1636 0 : if (heap->reserve) {
1637 0 : _zend_mm_free_int(heap, heap->reserve ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC);
1638 0 : heap->reserve = NULL;
1639 : }
1640 0 : if (heap->overflow == 0) {
1641 : char *error_filename;
1642 : uint error_lineno;
1643 : TSRMLS_FETCH();
1644 0 : if (zend_is_compiling(TSRMLS_C)) {
1645 0 : error_filename = zend_get_compiled_filename(TSRMLS_C);
1646 0 : error_lineno = zend_get_compiled_lineno(TSRMLS_C);
1647 0 : } else if (EG(in_execution)) {
1648 0 : error_filename = EG(active_op_array)?EG(active_op_array)->filename:NULL;
1649 0 : error_lineno = EG(opline_ptr)?(*EG(opline_ptr))->lineno:0;
1650 : } else {
1651 0 : error_filename = NULL;
1652 0 : error_lineno = 0;
1653 : }
1654 0 : if (!error_filename) {
1655 0 : error_filename = "Unknown";
1656 : }
1657 0 : heap->overflow = 1;
1658 0 : zend_try {
1659 0 : zend_error_noreturn(E_ERROR,
1660 : format,
1661 : limit,
1662 : #if ZEND_DEBUG
1663 : filename,
1664 : lineno,
1665 : #endif
1666 : size);
1667 0 : } zend_catch {
1668 0 : if (heap->overflow == 2) {
1669 0 : fprintf(stderr, "\nFatal error: ");
1670 0 : fprintf(stderr,
1671 : format,
1672 : limit,
1673 : #if ZEND_DEBUG
1674 : filename,
1675 : lineno,
1676 : #endif
1677 : size);
1678 0 : fprintf(stderr, " in %s on line %d\n", error_filename, error_lineno);
1679 : }
1680 0 : } zend_end_try();
1681 : } else {
1682 0 : heap->overflow = 2;
1683 : }
1684 0 : zend_bailout();
1685 0 : }
1686 :
1687 : static zend_mm_free_block *zend_mm_search_large_block(zend_mm_heap *heap, size_t true_size)
1688 5125143 : {
1689 : zend_mm_free_block *best_fit;
1690 5125143 : size_t index = ZEND_MM_LARGE_BUCKET_INDEX(true_size);
1691 5125143 : size_t bitmap = heap->large_free_bitmap >> index;
1692 : zend_mm_free_block *p;
1693 :
1694 5125143 : if (bitmap == 0) {
1695 43369 : return NULL;
1696 : }
1697 :
1698 5081774 : if (UNEXPECTED((bitmap & 1) != 0)) {
1699 : /* Search for best "large" free block */
1700 1003583 : zend_mm_free_block *rst = NULL;
1701 : size_t m;
1702 1003583 : size_t best_size = -1;
1703 :
1704 1003583 : best_fit = NULL;
1705 1003583 : p = heap->large_free_buckets[index];
1706 1481857 : for (m = true_size << (ZEND_MM_NUM_BUCKETS - index); ; m <<= 1) {
1707 1481857 : if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
1708 381349 : return p->next_free_block;
1709 1100508 : } else if (ZEND_MM_FREE_BLOCK_SIZE(p) >= true_size &&
1710 : ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
1711 440951 : best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
1712 440951 : best_fit = p;
1713 : }
1714 1100508 : if ((m & (ZEND_MM_LONG_CONST(1) << (ZEND_MM_NUM_BUCKETS-1))) == 0) {
1715 518119 : if (p->child[1]) {
1716 149884 : rst = p->child[1];
1717 : }
1718 518119 : if (p->child[0]) {
1719 238988 : p = p->child[0];
1720 : } else {
1721 279131 : break;
1722 : }
1723 582389 : } else if (p->child[1]) {
1724 239286 : p = p->child[1];
1725 : } else {
1726 343103 : break;
1727 : }
1728 478274 : }
1729 :
1730 721970 : for (p = rst; p; p = p->child[p->child[0] != NULL]) {
1731 99736 : if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
1732 0 : return p->next_free_block;
1733 99736 : } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
1734 : ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
1735 35222 : best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
1736 35222 : best_fit = p;
1737 : }
1738 : }
1739 :
1740 622234 : if (best_fit) {
1741 308168 : return best_fit->next_free_block;
1742 : }
1743 314066 : bitmap = bitmap >> 1;
1744 314066 : if (!bitmap) {
1745 386 : return NULL;
1746 : }
1747 313680 : index++;
1748 : }
1749 :
1750 : /* Search for smallest "large" free block */
1751 4391871 : best_fit = p = heap->large_free_buckets[index + zend_mm_low_bit(bitmap)];
1752 9074989 : while ((p = p->child[p->child[0] != NULL])) {
1753 291247 : if (ZEND_MM_FREE_BLOCK_SIZE(p) < ZEND_MM_FREE_BLOCK_SIZE(best_fit)) {
1754 90416 : best_fit = p;
1755 : }
1756 : }
1757 4391871 : return best_fit->next_free_block;
1758 : }
1759 :
1760 : static void *_zend_mm_alloc_int(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
1761 58569023 : {
1762 : zend_mm_free_block *best_fit;
1763 58569023 : size_t true_size = ZEND_MM_TRUE_SIZE(size);
1764 : size_t block_size;
1765 : size_t remaining_size;
1766 : size_t segment_size;
1767 : zend_mm_segment *segment;
1768 58569023 : int keep_rest = 0;
1769 :
1770 58569023 : if (EXPECTED(ZEND_MM_SMALL_SIZE(true_size))) {
1771 57103952 : size_t index = ZEND_MM_BUCKET_INDEX(true_size);
1772 : size_t bitmap;
1773 :
1774 57103952 : if (UNEXPECTED(true_size < size)) {
1775 0 : goto out_of_memory;
1776 : }
1777 : #if ZEND_MM_CACHE
1778 57103952 : if (EXPECTED(heap->cache[index] != NULL)) {
1779 : /* Get block from cache */
1780 : #if ZEND_MM_CACHE_STAT
1781 : heap->cache_stat[index].count--;
1782 : heap->cache_stat[index].hit++;
1783 : #endif
1784 35276407 : best_fit = heap->cache[index];
1785 35276407 : heap->cache[index] = best_fit->prev_free_block;
1786 35276407 : heap->cached -= true_size;
1787 : ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
1788 : ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
1789 35276407 : return ZEND_MM_DATA_OF(best_fit);
1790 : }
1791 : #if ZEND_MM_CACHE_STAT
1792 : heap->cache_stat[index].miss++;
1793 : #endif
1794 : #endif
1795 :
1796 21827545 : bitmap = heap->free_bitmap >> index;
1797 21827545 : if (bitmap) {
1798 : /* Found some "small" free block that can be used */
1799 18167473 : index += zend_mm_low_bit(bitmap);
1800 18167473 : best_fit = heap->free_buckets[index*2];
1801 : #if ZEND_MM_CACHE_STAT
1802 : heap->cache_stat[ZEND_MM_NUM_BUCKETS].hit++;
1803 : #endif
1804 18167473 : goto zend_mm_finished_searching_for_block;
1805 : }
1806 : }
1807 :
1808 : #if ZEND_MM_CACHE_STAT
1809 : heap->cache_stat[ZEND_MM_NUM_BUCKETS].miss++;
1810 : #endif
1811 :
1812 5125143 : best_fit = zend_mm_search_large_block(heap, true_size);
1813 :
1814 5125143 : if (!best_fit && heap->real_size >= heap->limit - heap->block_size) {
1815 0 : zend_mm_free_block *p = heap->rest_buckets[0];
1816 0 : size_t best_size = -1;
1817 :
1818 0 : while (p != ZEND_MM_REST_BUCKET(heap)) {
1819 0 : if (UNEXPECTED(ZEND_MM_FREE_BLOCK_SIZE(p) == true_size)) {
1820 0 : best_fit = p;
1821 0 : goto zend_mm_finished_searching_for_block;
1822 0 : } else if (ZEND_MM_FREE_BLOCK_SIZE(p) > true_size &&
1823 : ZEND_MM_FREE_BLOCK_SIZE(p) < best_size) {
1824 0 : best_size = ZEND_MM_FREE_BLOCK_SIZE(p);
1825 0 : best_fit = p;
1826 : }
1827 0 : p = p->prev_free_block;
1828 : }
1829 : }
1830 :
1831 5125143 : if (!best_fit) {
1832 43755 : if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
1833 : /* Make sure we add a memory block which is big enough,
1834 : segment must have header "size" and trailer "guard" block */
1835 4 : segment_size = true_size + ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE;
1836 4 : segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
1837 4 : keep_rest = 1;
1838 : } else {
1839 43751 : segment_size = heap->block_size;
1840 : }
1841 :
1842 43755 : HANDLE_BLOCK_INTERRUPTIONS();
1843 :
1844 43755 : if (segment_size < true_size ||
1845 : heap->real_size + segment_size > heap->limit) {
1846 : /* Memory limit overflow */
1847 : #if ZEND_MM_CACHE
1848 0 : zend_mm_free_cache(heap);
1849 : #endif
1850 0 : HANDLE_UNBLOCK_INTERRUPTIONS();
1851 : #if ZEND_DEBUG
1852 : 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);
1853 : #else
1854 0 : zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %lu bytes)", heap->limit, size);
1855 : #endif
1856 : }
1857 :
1858 43755 : segment = (zend_mm_segment *) ZEND_MM_STORAGE_ALLOC(segment_size);
1859 :
1860 43755 : if (!segment) {
1861 : /* Storage manager cannot allocate memory */
1862 : #if ZEND_MM_CACHE
1863 0 : zend_mm_free_cache(heap);
1864 : #endif
1865 0 : HANDLE_UNBLOCK_INTERRUPTIONS();
1866 0 : out_of_memory:
1867 : #if ZEND_DEBUG
1868 : 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);
1869 : #else
1870 0 : zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %lu bytes)", heap->real_size, size);
1871 : #endif
1872 0 : return NULL;
1873 : }
1874 :
1875 43755 : heap->real_size += segment_size;
1876 43755 : if (heap->real_size > heap->real_peak) {
1877 40729 : heap->real_peak = heap->real_size;
1878 : }
1879 :
1880 43755 : segment->size = segment_size;
1881 43755 : segment->next_segment = heap->segments_list;
1882 43755 : heap->segments_list = segment;
1883 :
1884 43755 : best_fit = (zend_mm_free_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
1885 43755 : ZEND_MM_MARK_FIRST_BLOCK(best_fit);
1886 :
1887 43755 : block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
1888 :
1889 43755 : ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(best_fit, block_size));
1890 :
1891 : } else {
1892 23248861 : zend_mm_finished_searching_for_block:
1893 : /* remove from free list */
1894 23248861 : HANDLE_BLOCK_INTERRUPTIONS();
1895 : ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_FREED);
1896 : ZEND_MM_CHECK_COOKIE(best_fit);
1897 23248861 : ZEND_MM_CHECK_BLOCK_LINKAGE(best_fit);
1898 23248861 : zend_mm_remove_from_free_list(heap, best_fit);
1899 :
1900 23248861 : block_size = ZEND_MM_FREE_BLOCK_SIZE(best_fit);
1901 : }
1902 :
1903 23292616 : remaining_size = block_size - true_size;
1904 :
1905 23292616 : if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
1906 15010422 : true_size = block_size;
1907 15010422 : ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
1908 : } else {
1909 : zend_mm_free_block *new_free_block;
1910 :
1911 : /* prepare new free block */
1912 8282194 : ZEND_MM_BLOCK(best_fit, ZEND_MM_USED_BLOCK, true_size);
1913 8282194 : new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(best_fit, true_size);
1914 8282194 : ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
1915 :
1916 : /* add the new free block to the free list */
1917 8282194 : if (EXPECTED(!keep_rest)) {
1918 8282190 : zend_mm_add_to_free_list(heap, new_free_block);
1919 : } else {
1920 4 : zend_mm_add_to_rest_list(heap, new_free_block);
1921 : }
1922 : }
1923 :
1924 : ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 1);
1925 :
1926 23292616 : heap->size += true_size;
1927 23292616 : if (heap->peak < heap->size) {
1928 93272 : heap->peak = heap->size;
1929 : }
1930 :
1931 23292616 : HANDLE_UNBLOCK_INTERRUPTIONS();
1932 :
1933 23292616 : return ZEND_MM_DATA_OF(best_fit);
1934 : }
1935 :
1936 :
1937 : static void _zend_mm_free_int(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
1938 58527890 : {
1939 : zend_mm_block *mm_block;
1940 : zend_mm_block *next_block;
1941 : size_t size;
1942 :
1943 58527890 : if (!ZEND_MM_VALID_PTR(p)) {
1944 0 : return;
1945 : }
1946 :
1947 58527890 : mm_block = ZEND_MM_HEADER_OF(p);
1948 58527890 : size = ZEND_MM_BLOCK_SIZE(mm_block);
1949 : ZEND_MM_CHECK_PROTECTION(mm_block);
1950 :
1951 : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
1952 : memset(ZEND_MM_DATA_OF(mm_block), 0x5a, mm_block->debug.size);
1953 : #endif
1954 :
1955 : #if ZEND_MM_CACHE
1956 58527890 : if (EXPECTED(ZEND_MM_SMALL_SIZE(size)) && EXPECTED(heap->cached < ZEND_MM_CACHE_SIZE)) {
1957 35279774 : size_t index = ZEND_MM_BUCKET_INDEX(size);
1958 35279774 : zend_mm_free_block **cache = &heap->cache[index];
1959 :
1960 35279774 : ((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
1961 35279774 : *cache = (zend_mm_free_block*)mm_block;
1962 35279774 : heap->cached += size;
1963 : ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
1964 : #if ZEND_MM_CACHE_STAT
1965 : if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
1966 : heap->cache_stat[index].max_count = heap->cache_stat[index].count;
1967 : }
1968 : #endif
1969 35279774 : return;
1970 : }
1971 : #endif
1972 :
1973 23248116 : HANDLE_BLOCK_INTERRUPTIONS();
1974 :
1975 23248116 : heap->size -= size;
1976 :
1977 23248116 : next_block = ZEND_MM_BLOCK_AT(mm_block, size);
1978 23248116 : if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
1979 4357021 : zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
1980 4357021 : size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
1981 : }
1982 23248116 : if (ZEND_MM_PREV_BLOCK_IS_FREE(mm_block)) {
1983 3865161 : mm_block = ZEND_MM_PREV_BLOCK(mm_block);
1984 3865161 : zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) mm_block);
1985 3865161 : size += ZEND_MM_FREE_BLOCK_SIZE(mm_block);
1986 : }
1987 23251145 : if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
1988 : ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(mm_block, size))) {
1989 3029 : zend_mm_del_segment(heap, (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE));
1990 : } else {
1991 23245087 : ZEND_MM_BLOCK(mm_block, ZEND_MM_FREE_BLOCK, size);
1992 23245087 : zend_mm_add_to_free_list(heap, (zend_mm_free_block *) mm_block);
1993 : }
1994 23248116 : HANDLE_UNBLOCK_INTERRUPTIONS();
1995 : }
1996 :
1997 : static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
1998 9168517 : {
1999 9168517 : zend_mm_block *mm_block = ZEND_MM_HEADER_OF(p);
2000 : zend_mm_block *next_block;
2001 : size_t true_size;
2002 : size_t orig_size;
2003 : void *ptr;
2004 :
2005 9168517 : if (UNEXPECTED(!p) || !ZEND_MM_VALID_PTR(p)) {
2006 4251103 : return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2007 : }
2008 4917414 : mm_block = ZEND_MM_HEADER_OF(p);
2009 4917414 : true_size = ZEND_MM_TRUE_SIZE(size);
2010 4917414 : orig_size = ZEND_MM_BLOCK_SIZE(mm_block);
2011 : ZEND_MM_CHECK_PROTECTION(mm_block);
2012 :
2013 4917414 : if (UNEXPECTED(true_size < size)) {
2014 0 : goto out_of_memory;
2015 : }
2016 :
2017 4917414 : if (true_size <= orig_size) {
2018 1731014 : size_t remaining_size = orig_size - true_size;
2019 :
2020 1731014 : if (remaining_size >= ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
2021 : zend_mm_free_block *new_free_block;
2022 :
2023 32724 : HANDLE_BLOCK_INTERRUPTIONS();
2024 32724 : next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
2025 32724 : if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
2026 9531 : remaining_size += ZEND_MM_FREE_BLOCK_SIZE(next_block);
2027 9531 : zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
2028 : }
2029 :
2030 : /* prepare new free block */
2031 32724 : ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2032 32724 : new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
2033 :
2034 32724 : ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
2035 :
2036 : /* add the new free block to the free list */
2037 32724 : zend_mm_add_to_free_list(heap, new_free_block);
2038 32724 : heap->size += (true_size - orig_size);
2039 32724 : HANDLE_UNBLOCK_INTERRUPTIONS();
2040 : }
2041 : ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
2042 1731014 : return p;
2043 : }
2044 :
2045 : #if ZEND_MM_CACHE
2046 3186400 : if (ZEND_MM_SMALL_SIZE(true_size)) {
2047 1616713 : size_t index = ZEND_MM_BUCKET_INDEX(true_size);
2048 :
2049 1616713 : if (heap->cache[index] != NULL) {
2050 : zend_mm_free_block *best_fit;
2051 : zend_mm_free_block **cache;
2052 :
2053 : #if ZEND_MM_CACHE_STAT
2054 : heap->cache_stat[index].count--;
2055 : heap->cache_stat[index].hit++;
2056 : #endif
2057 1283822 : best_fit = heap->cache[index];
2058 1283822 : heap->cache[index] = best_fit->prev_free_block;
2059 : ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
2060 : ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
2061 :
2062 1283822 : ptr = ZEND_MM_DATA_OF(best_fit);
2063 :
2064 : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2065 : memcpy(ptr, p, mm_block->debug.size);
2066 : #else
2067 1283822 : memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
2068 : #endif
2069 :
2070 1283822 : heap->cached -= true_size - orig_size;
2071 :
2072 1283822 : index = ZEND_MM_BUCKET_INDEX(orig_size);
2073 1283822 : cache = &heap->cache[index];
2074 :
2075 1283822 : ((zend_mm_free_block*)mm_block)->prev_free_block = *cache;
2076 1283822 : *cache = (zend_mm_free_block*)mm_block;
2077 : ZEND_MM_SET_MAGIC(mm_block, MEM_BLOCK_CACHED);
2078 : #if ZEND_MM_CACHE_STAT
2079 : if (++heap->cache_stat[index].count > heap->cache_stat[index].max_count) {
2080 : heap->cache_stat[index].max_count = heap->cache_stat[index].count;
2081 : }
2082 : #endif
2083 :
2084 1283822 : return ptr;
2085 : }
2086 : }
2087 : #endif
2088 :
2089 1902578 : next_block = ZEND_MM_BLOCK_AT(mm_block, orig_size);
2090 :
2091 1902578 : if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
2092 : ZEND_MM_CHECK_COOKIE(next_block);
2093 1404910 : ZEND_MM_CHECK_BLOCK_LINKAGE(next_block);
2094 1404910 : if (orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block) >= true_size) {
2095 1324000 : size_t block_size = orig_size + ZEND_MM_FREE_BLOCK_SIZE(next_block);
2096 1324000 : size_t remaining_size = block_size - true_size;
2097 :
2098 1324000 : HANDLE_BLOCK_INTERRUPTIONS();
2099 1324000 : zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
2100 :
2101 1324000 : if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
2102 36789 : true_size = block_size;
2103 36789 : ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2104 : } else {
2105 : zend_mm_free_block *new_free_block;
2106 :
2107 : /* prepare new free block */
2108 1287211 : ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2109 1287211 : new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
2110 1287211 : ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
2111 :
2112 : /* add the new free block to the free list */
2113 1297471 : if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
2114 : ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(new_free_block, remaining_size))) {
2115 10260 : zend_mm_add_to_rest_list(heap, new_free_block);
2116 : } else {
2117 1276951 : zend_mm_add_to_free_list(heap, new_free_block);
2118 : }
2119 : }
2120 : ZEND_MM_SET_DEBUG_INFO(mm_block, size, 0, 0);
2121 1324000 : heap->size = heap->size + true_size - orig_size;
2122 1324000 : if (heap->peak < heap->size) {
2123 8668 : heap->peak = heap->size;
2124 : }
2125 1324000 : HANDLE_UNBLOCK_INTERRUPTIONS();
2126 1324000 : return p;
2127 80910 : } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) &&
2128 : ZEND_MM_IS_GUARD_BLOCK(ZEND_MM_BLOCK_AT(next_block, ZEND_MM_FREE_BLOCK_SIZE(next_block)))) {
2129 0 : HANDLE_BLOCK_INTERRUPTIONS();
2130 0 : zend_mm_remove_from_free_list(heap, (zend_mm_free_block *) next_block);
2131 0 : goto realloc_segment;
2132 : }
2133 497668 : } else if (ZEND_MM_IS_FIRST_BLOCK(mm_block) && ZEND_MM_IS_GUARD_BLOCK(next_block)) {
2134 : zend_mm_segment *segment;
2135 : zend_mm_segment *segment_copy;
2136 : size_t segment_size;
2137 : size_t block_size;
2138 : size_t remaining_size;
2139 :
2140 0 : HANDLE_BLOCK_INTERRUPTIONS();
2141 0 : realloc_segment:
2142 : /* segment size, size of block and size of guard block */
2143 0 : if (true_size > heap->block_size - (ZEND_MM_ALIGNED_SEGMENT_SIZE + ZEND_MM_ALIGNED_HEADER_SIZE)) {
2144 0 : segment_size = true_size+ZEND_MM_ALIGNED_SEGMENT_SIZE+ZEND_MM_ALIGNED_HEADER_SIZE;
2145 0 : segment_size = (segment_size + (heap->block_size-1)) & ~(heap->block_size-1);
2146 : } else {
2147 0 : segment_size = heap->block_size;
2148 : }
2149 :
2150 0 : segment_copy = (zend_mm_segment *) ((char *)mm_block - ZEND_MM_ALIGNED_SEGMENT_SIZE);
2151 0 : if (segment_size < true_size ||
2152 : heap->real_size + segment_size - segment_copy->size > heap->limit) {
2153 0 : if (ZEND_MM_IS_FREE_BLOCK(next_block)) {
2154 0 : zend_mm_add_to_free_list(heap, (zend_mm_free_block *) next_block);
2155 : }
2156 : #if ZEND_MM_CACHE
2157 0 : zend_mm_free_cache(heap);
2158 : #endif
2159 0 : HANDLE_UNBLOCK_INTERRUPTIONS();
2160 : #if ZEND_DEBUG
2161 : 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);
2162 : #else
2163 0 : zend_mm_safe_error(heap, "Allowed memory size of %ld bytes exhausted (tried to allocate %ld bytes)", heap->limit, size);
2164 : #endif
2165 0 : return NULL;
2166 : }
2167 :
2168 0 : segment = ZEND_MM_STORAGE_REALLOC(segment_copy, segment_size);
2169 0 : if (!segment) {
2170 : #if ZEND_MM_CACHE
2171 0 : zend_mm_free_cache(heap);
2172 : #endif
2173 0 : HANDLE_UNBLOCK_INTERRUPTIONS();
2174 0 : out_of_memory:
2175 : #if ZEND_DEBUG
2176 : 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);
2177 : #else
2178 0 : zend_mm_safe_error(heap, "Out of memory (allocated %ld) (tried to allocate %ld bytes)", heap->real_size, size);
2179 : #endif
2180 0 : return NULL;
2181 : }
2182 0 : heap->real_size += segment_size - segment->size;
2183 0 : if (heap->real_size > heap->real_peak) {
2184 0 : heap->real_peak = heap->real_size;
2185 : }
2186 :
2187 0 : segment->size = segment_size;
2188 :
2189 0 : if (segment != segment_copy) {
2190 0 : zend_mm_segment **seg = &heap->segments_list;
2191 0 : while (*seg != segment_copy) {
2192 0 : seg = &(*seg)->next_segment;
2193 : }
2194 0 : *seg = segment;
2195 0 : mm_block = (zend_mm_block *) ((char *) segment + ZEND_MM_ALIGNED_SEGMENT_SIZE);
2196 0 : ZEND_MM_MARK_FIRST_BLOCK(mm_block);
2197 : }
2198 :
2199 0 : block_size = segment_size - ZEND_MM_ALIGNED_SEGMENT_SIZE - ZEND_MM_ALIGNED_HEADER_SIZE;
2200 0 : remaining_size = block_size - true_size;
2201 :
2202 : /* setup guard block */
2203 0 : ZEND_MM_LAST_BLOCK(ZEND_MM_BLOCK_AT(mm_block, block_size));
2204 :
2205 0 : if (remaining_size < ZEND_MM_ALIGNED_MIN_HEADER_SIZE) {
2206 0 : true_size = block_size;
2207 0 : ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2208 : } else {
2209 : zend_mm_free_block *new_free_block;
2210 :
2211 : /* prepare new free block */
2212 0 : ZEND_MM_BLOCK(mm_block, ZEND_MM_USED_BLOCK, true_size);
2213 0 : new_free_block = (zend_mm_free_block *) ZEND_MM_BLOCK_AT(mm_block, true_size);
2214 0 : ZEND_MM_BLOCK(new_free_block, ZEND_MM_FREE_BLOCK, remaining_size);
2215 :
2216 : /* add the new free block to the free list */
2217 0 : zend_mm_add_to_rest_list(heap, new_free_block);
2218 : }
2219 :
2220 : ZEND_MM_SET_DEBUG_INFO(mm_block, size, 1, 1);
2221 :
2222 0 : heap->size = heap->size + true_size - orig_size;
2223 0 : if (heap->peak < heap->size) {
2224 0 : heap->peak = heap->size;
2225 : }
2226 :
2227 0 : HANDLE_UNBLOCK_INTERRUPTIONS();
2228 0 : return ZEND_MM_DATA_OF(mm_block);
2229 : }
2230 :
2231 578578 : ptr = _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2232 : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2233 : memcpy(ptr, p, mm_block->debug.size);
2234 : #else
2235 578578 : memcpy(ptr, p, orig_size - ZEND_MM_ALIGNED_HEADER_SIZE);
2236 : #endif
2237 578578 : _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2238 578578 : return ptr;
2239 : }
2240 :
2241 : ZEND_API void *_zend_mm_alloc(zend_mm_heap *heap, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2242 0 : {
2243 0 : return _zend_mm_alloc_int(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2244 : }
2245 :
2246 : ZEND_API void _zend_mm_free(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2247 0 : {
2248 0 : _zend_mm_free_int(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2249 0 : }
2250 :
2251 : ZEND_API void *_zend_mm_realloc(zend_mm_heap *heap, void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2252 0 : {
2253 0 : return _zend_mm_realloc_int(heap, ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2254 : }
2255 :
2256 : ZEND_API size_t _zend_mm_block_size(zend_mm_heap *heap, void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2257 0 : {
2258 : zend_mm_block *mm_block;
2259 :
2260 0 : if (!ZEND_MM_VALID_PTR(p)) {
2261 0 : return 0;
2262 : }
2263 0 : mm_block = ZEND_MM_HEADER_OF(p);
2264 : ZEND_MM_CHECK_PROTECTION(mm_block);
2265 : #if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
2266 : return mm_block->debug.size;
2267 : #else
2268 0 : return ZEND_MM_BLOCK_SIZE(mm_block);
2269 : #endif
2270 : }
2271 :
2272 : /**********************/
2273 : /* Allocation Manager */
2274 : /**********************/
2275 :
2276 : typedef struct _zend_alloc_globals {
2277 : zend_mm_heap *mm_heap;
2278 : } zend_alloc_globals;
2279 :
2280 : #ifdef ZTS
2281 : static int alloc_globals_id;
2282 : # define AG(v) TSRMG(alloc_globals_id, zend_alloc_globals *, v)
2283 : #else
2284 : # define AG(v) (alloc_globals.v)
2285 : static zend_alloc_globals alloc_globals;
2286 : #endif
2287 :
2288 : ZEND_API int is_zend_mm(TSRMLS_D)
2289 3 : {
2290 3 : return AG(mm_heap)->use_zend_alloc;
2291 : }
2292 :
2293 : ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2294 125620490 : {
2295 : TSRMLS_FETCH();
2296 :
2297 125620490 : if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
2298 71921862 : return malloc(size);
2299 : }
2300 53698628 : return _zend_mm_alloc_int(AG(mm_heap), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2301 : }
2302 :
2303 : ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2304 132742570 : {
2305 : TSRMLS_FETCH();
2306 :
2307 132742570 : if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
2308 74793258 : free(ptr);
2309 74793258 : return;
2310 : }
2311 57949312 : _zend_mm_free_int(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2312 : }
2313 :
2314 : ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2315 12724560 : {
2316 : TSRMLS_FETCH();
2317 :
2318 12724560 : if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
2319 3556043 : return realloc(ptr, size);
2320 : }
2321 9168517 : return _zend_mm_realloc_int(AG(mm_heap), ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2322 : }
2323 :
2324 : ZEND_API size_t _zend_mem_block_size(void *ptr TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2325 0 : {
2326 0 : if (UNEXPECTED(!AG(mm_heap)->use_zend_alloc)) {
2327 0 : return 0;
2328 : }
2329 0 : return _zend_mm_block_size(AG(mm_heap), ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2330 : }
2331 :
2332 : #if defined(__GNUC__) && defined(i386)
2333 :
2334 : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
2335 9394495 : {
2336 9394495 : size_t res = nmemb;
2337 9394495 : unsigned long overflow = 0;
2338 :
2339 9394495 : __asm__ ("mull %3\n\taddl %4,%0\n\tadcl %1,%1"
2340 : : "=&a"(res), "=&d" (overflow)
2341 : : "%0"(res),
2342 : "rm"(size),
2343 : "rm"(offset));
2344 :
2345 9394495 : if (UNEXPECTED(overflow)) {
2346 0 : zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2347 : return 0;
2348 : }
2349 9394495 : return res;
2350 : }
2351 :
2352 : #elif defined(__GNUC__) && defined(__x86_64__)
2353 :
2354 : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
2355 : {
2356 : size_t res = nmemb;
2357 : unsigned long overflow = 0;
2358 :
2359 : __asm__ ("mulq %3\n\taddq %4,%0\n\tadcq %1,%1"
2360 : : "=&a"(res), "=&d" (overflow)
2361 : : "%0"(res),
2362 : "rm"(size),
2363 : "rm"(offset));
2364 :
2365 : if (UNEXPECTED(overflow)) {
2366 : zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2367 : return 0;
2368 : }
2369 : return res;
2370 : }
2371 :
2372 : #else
2373 :
2374 : static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
2375 : {
2376 : size_t res = nmemb * size + offset;
2377 : double _d = (double)nmemb * (double)size + (double)offset;
2378 : double _delta = (double)res - _d;
2379 :
2380 : if (UNEXPECTED((_d + _delta ) != _d)) {
2381 : zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
2382 : return 0;
2383 : }
2384 : return res;
2385 : }
2386 : #endif
2387 :
2388 :
2389 : ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2390 9298362 : {
2391 9298362 : return emalloc_rel(safe_address(nmemb, size, offset));
2392 : }
2393 :
2394 : ZEND_API void *_safe_malloc(size_t nmemb, size_t size, size_t offset)
2395 94957 : {
2396 94957 : return pemalloc(safe_address(nmemb, size, offset), 1);
2397 : }
2398 :
2399 : 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)
2400 1176 : {
2401 1176 : return erealloc_rel(ptr, safe_address(nmemb, size, offset));
2402 : }
2403 :
2404 : ZEND_API void *_safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset)
2405 0 : {
2406 0 : return perealloc(ptr, safe_address(nmemb, size, offset), 1);
2407 : }
2408 :
2409 :
2410 : ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2411 7239892 : {
2412 : void *p;
2413 :
2414 7239892 : p = _safe_emalloc(nmemb, size, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2415 7239892 : if (UNEXPECTED(p == NULL)) {
2416 0 : return p;
2417 : }
2418 7239892 : memset(p, 0, size * nmemb);
2419 7239892 : return p;
2420 : }
2421 :
2422 : ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2423 1725713 : {
2424 : int length;
2425 : char *p;
2426 :
2427 1725713 : length = strlen(s)+1;
2428 1725713 : p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2429 1725713 : if (UNEXPECTED(p == NULL)) {
2430 0 : return p;
2431 : }
2432 1725713 : memcpy(p, s, length);
2433 1725713 : return p;
2434 : }
2435 :
2436 : ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2437 17592802 : {
2438 : char *p;
2439 :
2440 17592802 : p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2441 17592802 : if (UNEXPECTED(p == NULL)) {
2442 0 : return p;
2443 : }
2444 17592802 : memcpy(p, s, length);
2445 17592802 : p[length] = 0;
2446 17592802 : return p;
2447 : }
2448 :
2449 :
2450 : ZEND_API char *zend_strndup(const char *s, uint length)
2451 30068481 : {
2452 : char *p;
2453 :
2454 30068481 : p = (char *) malloc(length+1);
2455 30068481 : if (UNEXPECTED(p == NULL)) {
2456 0 : return p;
2457 : }
2458 30068481 : if (length) {
2459 29730572 : memcpy(p, s, length);
2460 : }
2461 30068481 : p[length] = 0;
2462 30068481 : return p;
2463 : }
2464 :
2465 :
2466 : ZEND_API int zend_set_memory_limit(size_t memory_limit)
2467 13929 : {
2468 : TSRMLS_FETCH();
2469 :
2470 13929 : AG(mm_heap)->limit = (memory_limit >= AG(mm_heap)->block_size) ? memory_limit : AG(mm_heap)->block_size;
2471 :
2472 13929 : return SUCCESS;
2473 : }
2474 :
2475 : ZEND_API size_t zend_memory_usage(int real_usage TSRMLS_DC)
2476 1 : {
2477 1 : if (real_usage) {
2478 0 : return AG(mm_heap)->real_size;
2479 : } else {
2480 1 : size_t usage = AG(mm_heap)->size;
2481 : #if ZEND_MM_CACHE
2482 1 : usage -= AG(mm_heap)->cached;
2483 : #endif
2484 1 : return usage;
2485 : }
2486 : }
2487 :
2488 : ZEND_API size_t zend_memory_peak_usage(int real_usage TSRMLS_DC)
2489 1 : {
2490 1 : if (real_usage) {
2491 0 : return AG(mm_heap)->real_peak;
2492 : } else {
2493 1 : return AG(mm_heap)->peak;
2494 : }
2495 : }
2496 :
2497 : ZEND_API void shutdown_memory_manager(int silent, int full_shutdown TSRMLS_DC)
2498 40746 : {
2499 40746 : zend_mm_shutdown(AG(mm_heap), full_shutdown, silent);
2500 40746 : }
2501 :
2502 : static void alloc_globals_ctor(zend_alloc_globals *alloc_globals TSRMLS_DC)
2503 13565 : {
2504 : char *tmp;
2505 13565 : alloc_globals->mm_heap = zend_mm_startup();
2506 :
2507 13565 : tmp = getenv("USE_ZEND_ALLOC");
2508 13565 : if (tmp) {
2509 13561 : alloc_globals->mm_heap->use_zend_alloc = zend_atoi(tmp, 0);
2510 : }
2511 13565 : }
2512 :
2513 : #ifdef ZTS
2514 : static void alloc_globals_dtor(zend_alloc_globals *alloc_globals TSRMLS_DC)
2515 : {
2516 : shutdown_memory_manager(1, 1 TSRMLS_CC);
2517 : }
2518 : #endif
2519 :
2520 : ZEND_API void start_memory_manager(TSRMLS_D)
2521 13565 : {
2522 : #ifdef ZTS
2523 : ts_allocate_id(&alloc_globals_id, sizeof(zend_alloc_globals), (ts_allocate_ctor) alloc_globals_ctor, (ts_allocate_dtor) alloc_globals_dtor);
2524 : #else
2525 13565 : alloc_globals_ctor(&alloc_globals);
2526 : #endif
2527 13565 : }
2528 :
2529 : ZEND_API zend_mm_heap *zend_mm_set_heap(zend_mm_heap *new_heap TSRMLS_DC)
2530 0 : {
2531 : zend_mm_heap *old_heap;
2532 :
2533 0 : old_heap = AG(mm_heap);
2534 0 : AG(mm_heap) = new_heap;
2535 0 : return old_heap;
2536 : }
2537 :
2538 : ZEND_API zend_mm_storage *zend_mm_get_storage(zend_mm_heap *heap)
2539 0 : {
2540 0 : return heap->storage;
2541 : }
2542 :
2543 : #if ZEND_DEBUG
2544 : ZEND_API int _mem_block_check(void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2545 : {
2546 : TSRMLS_FETCH();
2547 :
2548 : if (!AG(mm_heap)->use_zend_alloc) {
2549 : return 1;
2550 : }
2551 : return zend_mm_check_ptr(AG(mm_heap), ptr, silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2552 : }
2553 :
2554 :
2555 : ZEND_API void _full_mem_check(int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
2556 : {
2557 : int errors;
2558 : TSRMLS_FETCH();
2559 :
2560 : if (!AG(mm_heap)->use_zend_alloc) {
2561 : return;
2562 : }
2563 :
2564 : zend_debug_alloc_output("------------------------------------------------\n");
2565 : zend_debug_alloc_output("Full Memory Check at %s:%d\n" ZEND_FILE_LINE_RELAY_CC);
2566 :
2567 : errors = zend_mm_check_heap(AG(mm_heap), silent ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
2568 :
2569 : zend_debug_alloc_output("End of full memory check %s:%d (%d errors)\n" ZEND_FILE_LINE_RELAY_CC, errors);
2570 : zend_debug_alloc_output("------------------------------------------------\n");
2571 : }
2572 : #endif
2573 :
2574 : /*
2575 : * Local variables:
2576 : * tab-width: 4
2577 : * c-basic-offset: 4
2578 : * indent-tabs-mode: t
2579 : * End:
2580 : */
|