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