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