~ubuntu-branches/ubuntu/hardy/php5/hardy-updates

« back to all changes in this revision

Viewing changes to Zend/zend_alloc.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-10-09 03:14:32 UTC
  • Revision ID: james.westby@ubuntu.com-20051009031432-kspik3lobxstafv9
Tags: upstream-5.0.5
ImportĀ upstreamĀ versionĀ 5.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   +----------------------------------------------------------------------+
 
3
   | Zend Engine                                                          |
 
4
   +----------------------------------------------------------------------+
 
5
   | Copyright (c) 1998-2004 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
   +----------------------------------------------------------------------+
 
18
*/
 
19
 
 
20
/* $Id: zend_alloc.c,v 1.137.2.4 2005/08/18 15:14:23 iliaa Exp $ */
 
21
 
 
22
#include "zend.h"
 
23
#include "zend_alloc.h"
 
24
#include "zend_globals.h"
 
25
#include "zend_fast_cache.h"
 
26
#ifdef HAVE_SIGNAL_H
 
27
# include <signal.h>
 
28
#endif
 
29
#ifdef HAVE_UNISTD_H
 
30
# include <unistd.h>
 
31
#endif
 
32
 
 
33
#include "zend_mm.h"
 
34
 
 
35
#ifndef ZTS
 
36
ZEND_API zend_alloc_globals alloc_globals;
 
37
#endif
 
38
 
 
39
 
 
40
#ifdef ZEND_MM
 
41
#define ZEND_DISABLE_MEMORY_CACHE 0
 
42
#else
 
43
#define ZEND_DISABLE_MEMORY_CACHE 0
 
44
#endif
 
45
 
 
46
#ifdef ZEND_MM
 
47
#define ZEND_DO_MALLOC(size)            zend_mm_alloc(&AG(mm_heap), size)
 
48
#define ZEND_DO_FREE(ptr)                       zend_mm_free(&AG(mm_heap), ptr)
 
49
#define ZEND_DO_REALLOC(ptr, size)      zend_mm_realloc(&AG(mm_heap), ptr, size)
 
50
#elif defined(ZEND_WIN32)
 
51
#define ZEND_DO_MALLOC(size)            (AG(memory_heap) ? HeapAlloc(AG(memory_heap), HEAP_NO_SERIALIZE, size) : malloc(size))
 
52
#define ZEND_DO_FREE(ptr)                       (AG(memory_heap) ? HeapFree(AG(memory_heap), HEAP_NO_SERIALIZE, ptr) : free(ptr))
 
53
#define ZEND_DO_REALLOC(ptr, size)      (AG(memory_heap) ? HeapReAlloc(AG(memory_heap), HEAP_NO_SERIALIZE, ptr, size) : realloc(ptr, size))
 
54
#else
 
55
#define ZEND_DO_MALLOC(size)            malloc(size)
 
56
#define ZEND_DO_FREE(ptr)                       free(ptr)
 
57
#define ZEND_DO_REALLOC(ptr, size)      realloc(ptr, size)
 
58
#endif
 
59
 
 
60
#if ZEND_DEBUG
 
61
# define END_MAGIC_SIZE sizeof(long)
 
62
static long mem_block_end_magic = MEM_BLOCK_END_MAGIC;
 
63
#else
 
64
# define END_MAGIC_SIZE 0
 
65
#endif
 
66
 
 
67
 
 
68
# if MEMORY_LIMIT
 
69
#  if ZEND_DEBUG
 
70
#define CHECK_MEMORY_LIMIT(s, rs) _CHECK_MEMORY_LIMIT(s, rs, __zend_filename, __zend_lineno)
 
71
#  else
 
72
#define CHECK_MEMORY_LIMIT(s, rs)       _CHECK_MEMORY_LIMIT(s, rs, NULL, 0)
 
73
#  endif
 
74
 
 
75
#define _CHECK_MEMORY_LIMIT(s, rs, file, lineno) { AG(allocated_memory) += rs;\
 
76
                                                                if (AG(memory_limit)<AG(allocated_memory)) {\
 
77
                                                                        int php_mem_limit = AG(memory_limit); \
 
78
                                                                        AG(allocated_memory) -= rs; \
 
79
                                                                        if (EG(in_execution) && AG(memory_limit)+1048576 > AG(allocated_memory)) { \
 
80
                                                                                AG(memory_limit) = AG(allocated_memory) + 1048576; \
 
81
                                                                                if (file) { \
 
82
                                                                                        zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted at %s:%d (tried to allocate %d bytes)", php_mem_limit, file, lineno, s); \
 
83
                                                                                } else { \
 
84
                                                                                        zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted (tried to allocate %d bytes)", php_mem_limit, s); \
 
85
                                                                                } \
 
86
                                                                        } else { \
 
87
                                                                                if (file) { \
 
88
                                                                                        fprintf(stderr, "Allowed memory size of %d bytes exhausted at %s:%d (tried to allocate %d bytes)\n", php_mem_limit, file, lineno, s); \
 
89
                                                                                } else { \
 
90
                                                                                        fprintf(stderr, "Allowed memory size of %d bytes exhausted (tried to allocate %d bytes)\n", php_mem_limit, s); \
 
91
                                                                                } \
 
92
                                                                                exit(1); \
 
93
                                                                        } \
 
94
                                                                } \
 
95
                                                        }
 
96
# endif
 
97
 
 
98
#ifndef CHECK_MEMORY_LIMIT
 
99
#define CHECK_MEMORY_LIMIT(s, rs)
 
100
#endif
 
101
 
 
102
 
 
103
#if ZEND_DEBUG || !defined(ZEND_MM)
 
104
#define REMOVE_POINTER_FROM_LIST(p)                             \
 
105
        if (p==AG(head)) {                                                      \
 
106
                AG(head) = p->pNext;                                    \
 
107
        } else {                                                                        \
 
108
                p->pLast->pNext = p->pNext;                             \
 
109
        }                                                                                       \
 
110
        if (p->pNext) {                                                         \
 
111
                p->pNext->pLast = p->pLast;                             \
 
112
        }
 
113
#else
 
114
#define REMOVE_POINTER_FROM_LIST(p)
 
115
#endif
 
116
 
 
117
#if ZEND_DEBUG || !defined(ZEND_MM)
 
118
#define ADD_POINTER_TO_LIST(p)  \
 
119
        p->pNext = AG(head);            \
 
120
        if (AG(head)) {                         \
 
121
                AG(head)->pLast = p;    \
 
122
        }                                                       \
 
123
        AG(head) = p;                           \
 
124
        p->pLast = (zend_mem_header *) NULL;
 
125
#else
 
126
#define ADD_POINTER_TO_LIST(p)
 
127
#endif
 
128
 
 
129
#define DECLARE_CACHE_VARS()    \
 
130
        unsigned int real_size;         \
 
131
        unsigned int cache_index
 
132
 
 
133
#define REAL_SIZE(size) ((size+7) & ~0x7)
 
134
 
 
135
#define CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size)       \
 
136
        real_size = REAL_SIZE(size);                            \
 
137
        cache_index = real_size >> 3;
 
138
 
 
139
#define SIZE real_size
 
140
 
 
141
#define CACHE_INDEX cache_index
 
142
 
 
143
ZEND_API void *_emalloc(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
 
144
{
 
145
        zend_mem_header *p;
 
146
        DECLARE_CACHE_VARS();
 
147
        TSRMLS_FETCH();
 
148
 
 
149
        CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size);
 
150
 
 
151
#if !ZEND_DISABLE_MEMORY_CACHE
 
152
        if ((CACHE_INDEX < MAX_CACHED_MEMORY) && (AG(cache_count)[CACHE_INDEX] > 0)) {
 
153
                p = AG(cache)[CACHE_INDEX][--AG(cache_count)[CACHE_INDEX]];
 
154
#if ZEND_DEBUG
 
155
                p->filename = __zend_filename;
 
156
                p->lineno = __zend_lineno;
 
157
                p->orig_filename = __zend_orig_filename;
 
158
                p->orig_lineno = __zend_orig_lineno;
 
159
                p->magic = MEM_BLOCK_START_MAGIC;
 
160
                p->reported = 0;
 
161
                /* Setting the thread id should not be necessary, because we fetched this block
 
162
                 * from this thread's cache
 
163
                 */
 
164
                AG(cache_stats)[CACHE_INDEX][1]++;
 
165
                memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long));
 
166
#endif
 
167
                p->cached = 0;
 
168
                p->size = size;
 
169
                return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING);
 
170
        } else {
 
171
#endif
 
172
#if ZEND_DEBUG
 
173
                if (CACHE_INDEX<MAX_CACHED_MEMORY) {
 
174
                        AG(cache_stats)[CACHE_INDEX][0]++;
 
175
                }
 
176
#endif
 
177
#if MEMORY_LIMIT
 
178
                CHECK_MEMORY_LIMIT(size, SIZE);
 
179
                if (AG(allocated_memory) > AG(allocated_memory_peak)) {
 
180
                        AG(allocated_memory_peak) = AG(allocated_memory);
 
181
                }
 
182
#endif
 
183
                p  = (zend_mem_header *) ZEND_DO_MALLOC(sizeof(zend_mem_header) + MEM_HEADER_PADDING + SIZE + END_MAGIC_SIZE);
 
184
#if !ZEND_DISABLE_MEMORY_CACHE
 
185
        }
 
186
#endif
 
187
 
 
188
        HANDLE_BLOCK_INTERRUPTIONS();
 
189
 
 
190
        if (!p) {
 
191
                fprintf(stderr,"FATAL:  emalloc():  Unable to allocate %ld bytes\n", (long) size);
 
192
#if ZEND_DEBUG && defined(HAVE_KILL) && defined(HAVE_GETPID)
 
193
                kill(getpid(), SIGSEGV);
 
194
#else
 
195
                exit(1);
 
196
#endif
 
197
                HANDLE_UNBLOCK_INTERRUPTIONS();
 
198
                return (void *)p;
 
199
        }
 
200
        p->cached = 0;
 
201
        ADD_POINTER_TO_LIST(p);
 
202
        p->size = size; /* Save real size for correct cache output */
 
203
#if ZEND_DEBUG
 
204
        p->filename = __zend_filename;
 
205
        p->lineno = __zend_lineno;
 
206
        p->orig_filename = __zend_orig_filename;
 
207
        p->orig_lineno = __zend_orig_lineno;
 
208
        p->magic = MEM_BLOCK_START_MAGIC;
 
209
        p->reported = 0;
 
210
# ifdef ZTS
 
211
        p->thread_id = tsrm_thread_id();
 
212
# endif
 
213
        memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long));
 
214
#endif
 
215
 
 
216
        HANDLE_UNBLOCK_INTERRUPTIONS();
 
217
        return (void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING);
 
218
}
 
219
 
 
220
#include "zend_multiply.h"
 
221
 
 
222
ZEND_API void *_safe_emalloc(size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
 
223
{
 
224
 
 
225
        if (nmemb < LONG_MAX
 
226
                        && size < LONG_MAX
 
227
                        && offset < LONG_MAX
 
228
                        && nmemb >= 0
 
229
                        && size >= 0
 
230
                        && offset >= 0) {
 
231
                long lval;
 
232
                double dval;
 
233
                int use_dval;
 
234
 
 
235
                ZEND_SIGNED_MULTIPLY_LONG(nmemb, size, lval, dval, use_dval);
 
236
 
 
237
                if (!use_dval
 
238
                                && lval < (long) (LONG_MAX - offset)) {
 
239
                        return emalloc_rel(lval + offset);
 
240
                }
 
241
        }
 
242
 
 
243
        zend_error(E_ERROR, "Possible integer overflow in memory allocation (%zd * %zd + %zd)", nmemb, size, offset);
 
244
        return 0;
 
245
}
 
246
 
 
247
 
 
248
 
 
249
ZEND_API void _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
 
250
{
 
251
        zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING);
 
252
        DECLARE_CACHE_VARS();
 
253
        TSRMLS_FETCH();
 
254
 
 
255
#if defined(ZTS) && TSRM_DEBUG
 
256
        if (p->thread_id != tsrm_thread_id()) {
 
257
                tsrm_error(TSRM_ERROR_LEVEL_ERROR, "Memory block allocated at %s:(%d) on thread %x freed at %s:(%d) on thread %x, ignoring",
 
258
                        p->filename, p->lineno, p->thread_id,
 
259
                        __zend_filename, __zend_lineno, tsrm_thread_id());
 
260
                return;
 
261
        }
 
262
#endif
 
263
 
 
264
        CALCULATE_REAL_SIZE_AND_CACHE_INDEX(p->size);
 
265
#if ZEND_DEBUG
 
266
        if (!_mem_block_check(ptr, 1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC)) {
 
267
                return;
 
268
        }
 
269
        memset(ptr, 0x5a, p->size);
 
270
#endif
 
271
#if !ZEND_DISABLE_MEMORY_CACHE
 
272
        if ((CACHE_INDEX < MAX_CACHED_MEMORY) && (AG(cache_count)[CACHE_INDEX] < MAX_CACHED_ENTRIES)) {
 
273
                AG(cache)[CACHE_INDEX][AG(cache_count)[CACHE_INDEX]++] = p;
 
274
                p->cached = 1;
 
275
#if ZEND_DEBUG
 
276
                p->magic = MEM_BLOCK_CACHED_MAGIC;
 
277
#endif
 
278
                return;
 
279
        }
 
280
#endif
 
281
        HANDLE_BLOCK_INTERRUPTIONS();
 
282
        REMOVE_POINTER_FROM_LIST(p);
 
283
 
 
284
#if MEMORY_LIMIT
 
285
        AG(allocated_memory) -= SIZE;
 
286
#endif
 
287
        
 
288
        ZEND_DO_FREE(p);
 
289
        HANDLE_UNBLOCK_INTERRUPTIONS();
 
290
}
 
291
 
 
292
 
 
293
ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
 
294
{
 
295
        void *p;
 
296
        int final_size = size*nmemb;
 
297
        
 
298
        HANDLE_BLOCK_INTERRUPTIONS();
 
299
        p = _emalloc(final_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
 
300
        if (!p) {
 
301
                HANDLE_UNBLOCK_INTERRUPTIONS();
 
302
                return (void *) p;
 
303
        }
 
304
        memset(p, 0, final_size);
 
305
        HANDLE_UNBLOCK_INTERRUPTIONS();
 
306
        return p;
 
307
}
 
308
 
 
309
 
 
310
ZEND_API void *_erealloc(void *ptr, size_t size, int allow_failure ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
 
311
{
 
312
        zend_mem_header *p;
 
313
        zend_mem_header *orig;
 
314
        DECLARE_CACHE_VARS();
 
315
        TSRMLS_FETCH();
 
316
 
 
317
        if (!ptr) {
 
318
                return _emalloc(size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
 
319
        }
 
320
 
 
321
        p = orig = (zend_mem_header *) ((char *)ptr-sizeof(zend_mem_header)-MEM_HEADER_PADDING);
 
322
 
 
323
#if defined(ZTS) && TSRM_DEBUG
 
324
        if (p->thread_id != tsrm_thread_id()) {
 
325
                void *new_p;
 
326
 
 
327
                tsrm_error(TSRM_ERROR_LEVEL_ERROR, "Memory block allocated at %s:(%d) on thread %x reallocated at %s:(%d) on thread %x, duplicating",
 
328
                        p->filename, p->lineno, p->thread_id,
 
329
                        __zend_filename, __zend_lineno, tsrm_thread_id());
 
330
                new_p = _emalloc(size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
 
331
                memcpy(new_p, ptr, p->size);
 
332
                return new_p;
 
333
        }
 
334
#endif
 
335
 
 
336
        CALCULATE_REAL_SIZE_AND_CACHE_INDEX(size);
 
337
 
 
338
        HANDLE_BLOCK_INTERRUPTIONS();
 
339
#if MEMORY_LIMIT
 
340
        CHECK_MEMORY_LIMIT(size - p->size, SIZE - REAL_SIZE(p->size));
 
341
        if (AG(allocated_memory) > AG(allocated_memory_peak)) {
 
342
                AG(allocated_memory_peak) = AG(allocated_memory);
 
343
        }
 
344
#endif
 
345
        REMOVE_POINTER_FROM_LIST(p);
 
346
        p = (zend_mem_header *) ZEND_DO_REALLOC(p, sizeof(zend_mem_header)+MEM_HEADER_PADDING+SIZE+END_MAGIC_SIZE);
 
347
        if (!p) {
 
348
                if (!allow_failure) {
 
349
                        fprintf(stderr,"FATAL:  erealloc():  Unable to allocate %ld bytes\n", (long) size);
 
350
#if ZEND_DEBUG && HAVE_KILL && HAVE_GETPID
 
351
                        kill(getpid(), SIGSEGV);
 
352
#else
 
353
                        exit(1);
 
354
#endif
 
355
                }
 
356
                ADD_POINTER_TO_LIST(orig);
 
357
                HANDLE_UNBLOCK_INTERRUPTIONS();
 
358
                return (void *)NULL;
 
359
        }
 
360
        ADD_POINTER_TO_LIST(p);
 
361
#if ZEND_DEBUG
 
362
        p->filename = __zend_filename;
 
363
        p->lineno = __zend_lineno;
 
364
        p->magic = MEM_BLOCK_START_MAGIC;
 
365
        memcpy((((char *) p) + sizeof(zend_mem_header) + MEM_HEADER_PADDING + size), &mem_block_end_magic, sizeof(long));
 
366
#endif  
 
367
 
 
368
        p->size = size;
 
369
 
 
370
        HANDLE_UNBLOCK_INTERRUPTIONS();
 
371
        return (void *)((char *)p+sizeof(zend_mem_header)+MEM_HEADER_PADDING);
 
372
}
 
373
 
 
374
 
 
375
ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
 
376
{
 
377
        int length;
 
378
        char *p;
 
379
 
 
380
        length = strlen(s)+1;
 
381
        HANDLE_BLOCK_INTERRUPTIONS();
 
382
        p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
 
383
        if (!p) {
 
384
                HANDLE_UNBLOCK_INTERRUPTIONS();
 
385
                return (char *)NULL;
 
386
        }
 
387
        HANDLE_UNBLOCK_INTERRUPTIONS();
 
388
        memcpy(p, s, length);
 
389
        return p;
 
390
}
 
391
 
 
392
ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
 
393
{
 
394
        char *p;
 
395
 
 
396
        HANDLE_BLOCK_INTERRUPTIONS();
 
397
        p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
 
398
        if (!p) {
 
399
                HANDLE_UNBLOCK_INTERRUPTIONS();
 
400
                return (char *)NULL;
 
401
        }
 
402
        HANDLE_UNBLOCK_INTERRUPTIONS();
 
403
        memcpy(p, s, length);
 
404
        p[length] = 0;
 
405
        return p;
 
406
}
 
407
 
 
408
 
 
409
ZEND_API char *zend_strndup(const char *s, uint length)
 
410
{
 
411
        char *p;
 
412
 
 
413
        p = (char *) malloc(length+1);
 
414
        if (!p) {
 
415
                return (char *)NULL;
 
416
        }
 
417
        if (length) {
 
418
                memcpy(p, s, length);
 
419
        }
 
420
        p[length] = 0;
 
421
        return p;
 
422
}
 
423
 
 
424
 
 
425
ZEND_API int zend_set_memory_limit(unsigned int memory_limit)
 
426
{
 
427
#if MEMORY_LIMIT
 
428
        TSRMLS_FETCH();
 
429
 
 
430
        AG(memory_limit) = memory_limit;
 
431
        return SUCCESS;
 
432
#else
 
433
        return FAILURE;
 
434
#endif
 
435
}
 
436
 
 
437
 
 
438
ZEND_API void start_memory_manager(TSRMLS_D)
 
439
{
 
440
        AG(head) = NULL;
 
441
        
 
442
#if MEMORY_LIMIT
 
443
        AG(memory_limit) = 1<<30;               /* ridiculous limit, effectively no limit */
 
444
        AG(allocated_memory) = 0;
 
445
        AG(memory_exhausted) = 0;
 
446
        AG(allocated_memory_peak) = 0;
 
447
#endif
 
448
 
 
449
#if ZEND_ENABLE_FAST_CACHE
 
450
        memset(AG(fast_cache_list_head), 0, sizeof(AG(fast_cache_list_head)));
 
451
#endif
 
452
#if !ZEND_DISABLE_MEMORY_CACHE
 
453
        memset(AG(cache_count), 0, sizeof(AG(cache_count)));
 
454
#endif
 
455
 
 
456
#ifdef ZEND_MM
 
457
        zend_mm_startup(&AG(mm_heap), 256*1024);
 
458
#elif defined(ZEND_WIN32)
 
459
        AG(memory_heap) = HeapCreate(HEAP_NO_SERIALIZE, 256*1024, 0);
 
460
#endif
 
461
 
 
462
#if ZEND_DEBUG
 
463
        memset(AG(cache_stats), 0, sizeof(AG(cache_stats)));
 
464
        memset(AG(fast_cache_stats), 0, sizeof(AG(fast_cache_stats)));
 
465
#endif
 
466
}
 
467
 
 
468
 
 
469
ZEND_API void shutdown_memory_manager(int silent, int full_shutdown TSRMLS_DC)
 
470
{
 
471
#if ZEND_DEBUG || !defined(ZEND_MM)
 
472
        zend_mem_header *p, *t;
 
473
#endif
 
474
#if ZEND_DEBUG
 
475
        zend_uint grand_total_leaks=0;
 
476
#endif
 
477
 
 
478
#if !ZEND_DISABLE_MEMORY_CACHE
 
479
        /* Free memory cache even on partial shutdown to avoid fragmentation */
 
480
        if (1 || full_shutdown) {
 
481
                unsigned int i, j;
 
482
                zend_mem_header *ptr;
 
483
 
 
484
                for (i=0; i<MAX_CACHED_MEMORY; i++) {
 
485
                        for (j=0; j<AG(cache_count)[i]; j++) {
 
486
                                ptr = (zend_mem_header *) AG(cache)[i][j];
 
487
#  if MEMORY_LIMIT
 
488
                                AG(allocated_memory) -= REAL_SIZE(ptr->size);
 
489
#  endif
 
490
                                REMOVE_POINTER_FROM_LIST(ptr);
 
491
                                ZEND_DO_FREE(ptr);
 
492
                        }
 
493
                        AG(cache_count)[i] = 0;
 
494
                }
 
495
        }
 
496
#endif /* !ZEND_DISABLE_MEMORY_CACHE */
 
497
 
 
498
#if defined(ZEND_MM) && !ZEND_DEBUG
 
499
        zend_mm_shutdown(&AG(mm_heap));
 
500
        if (full_shutdown) {
 
501
                return;
 
502
        }
 
503
        zend_mm_startup(&AG(mm_heap), 256*1024);
 
504
 
 
505
#elif defined(ZEND_WIN32) && !ZEND_DEBUG
 
506
        if (full_shutdown && AG(memory_heap)) {
 
507
                HeapDestroy(AG(memory_heap));
 
508
                return;
 
509
        }
 
510
#endif
 
511
 
 
512
#if ZEND_ENABLE_FAST_CACHE
 
513
        {
 
514
                zend_fast_cache_list_entry *fast_cache_list_entry, *next_fast_cache_list_entry;
 
515
                unsigned int fci;
 
516
 
 
517
                for (fci=0; fci<MAX_FAST_CACHE_TYPES; fci++) {
 
518
                        fast_cache_list_entry = AG(fast_cache_list_head)[fci];
 
519
                        while (fast_cache_list_entry) {
 
520
                                next_fast_cache_list_entry = fast_cache_list_entry->next;
 
521
                                efree(fast_cache_list_entry);
 
522
                                fast_cache_list_entry = next_fast_cache_list_entry;
 
523
                        }
 
524
                        AG(fast_cache_list_head)[fci] = NULL;
 
525
                }
 
526
        }
 
527
#endif /* ZEND_ENABLE_FAST_CACHE */
 
528
 
 
529
#if ZEND_DEBUG || !defined(ZEND_MM)
 
530
        p = AG(head);
 
531
        t = AG(head);
 
532
        while (t) {
 
533
                if (!t->cached) {
 
534
#if ZEND_DEBUG
 
535
                        if (!t->reported) {
 
536
                                zend_mem_header *iterator;
 
537
                                int total_leak=0, total_leak_count=0;
 
538
 
 
539
                                grand_total_leaks++;
 
540
                                if (!silent) {
 
541
                                        zend_message_dispatcher(ZMSG_MEMORY_LEAK_DETECTED, t);
 
542
                                }
 
543
                                t->reported = 1;
 
544
                                for (iterator=t->pNext; iterator; iterator=iterator->pNext) {
 
545
                                        if (!iterator->cached
 
546
                                                && iterator->filename==t->filename
 
547
                                                && iterator->lineno==t->lineno) {
 
548
                                                total_leak += iterator->size;
 
549
                                                total_leak_count++;
 
550
                                                iterator->reported = 1;
 
551
                                        }
 
552
                                }
 
553
                                if (!silent && total_leak_count>0) {
 
554
                                        zend_message_dispatcher(ZMSG_MEMORY_LEAK_REPEATED, (void *) (long) (total_leak_count));
 
555
                                }
 
556
                                grand_total_leaks += total_leak_count;
 
557
                        }
 
558
#endif
 
559
#if MEMORY_LIMIT
 
560
                        AG(allocated_memory) -= REAL_SIZE(t->size);
 
561
#endif
 
562
                        p = t->pNext;
 
563
                        REMOVE_POINTER_FROM_LIST(t);
 
564
                        ZEND_DO_FREE(t);
 
565
                        t = p;
 
566
                } else {
 
567
                        t = t->pNext;
 
568
                }
 
569
        }
 
570
 
 
571
#if ZEND_DEBUG
 
572
        if (!silent && grand_total_leaks > 0) {
 
573
                zend_message_dispatcher(ZMSG_MEMORY_LEAKS_GRAND_TOTAL, &grand_total_leaks);
 
574
        }
 
575
#endif
 
576
 
 
577
#if MEMORY_LIMIT
 
578
        AG(memory_exhausted)=0;
 
579
        AG(allocated_memory_peak) = 0;
 
580
#endif
 
581
 
 
582
 
 
583
#if (ZEND_DEBUG)
 
584
        do {
 
585
                zval display_memory_cache_stats;
 
586
                int i, j;
 
587
 
 
588
                if (full_shutdown) {
 
589
                        /* we're shutting down completely, don't even touch the INI subsystem */
 
590
                        break;
 
591
                }
 
592
                if (zend_get_configuration_directive("display_memory_cache_stats", sizeof("display_memory_cache_stats"), &display_memory_cache_stats)==FAILURE) {
 
593
                        break;
 
594
                }
 
595
                if (!atoi(display_memory_cache_stats.value.str.val)) {
 
596
                        break;
 
597
                }
 
598
                fprintf(stderr, "Memory cache statistics\n"
 
599
                                                "-----------------------\n\n"
 
600
                                                "[zval, %2ld]\t\t%d / %d (%.2f%%)\n"
 
601
                                                "[hash, %2ld]\t\t%d / %d (%.2f%%)\n",
 
602
                                                (long) sizeof(zval),
 
603
                                                AG(fast_cache_stats)[ZVAL_CACHE_LIST][1], AG(fast_cache_stats)[ZVAL_CACHE_LIST][0]+AG(fast_cache_stats)[ZVAL_CACHE_LIST][1],
 
604
                                                ((double) AG(fast_cache_stats)[ZVAL_CACHE_LIST][1] / (AG(fast_cache_stats)[ZVAL_CACHE_LIST][0]+AG(fast_cache_stats)[ZVAL_CACHE_LIST][1]))*100,
 
605
                                                (long) sizeof(HashTable),
 
606
                                                AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][1], AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][0]+AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][1],
 
607
                                                ((double) AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][1] / (AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][0]+AG(fast_cache_stats)[HASHTABLE_CACHE_LIST][1]))*100);
 
608
 
 
609
 
 
610
                for (i=0; i<MAX_CACHED_MEMORY; i+=2) {
 
611
                        fprintf(stderr, "[%2d, %2d]\t\t", i, i+1);
 
612
                        for (j=0; j<2; j++) {
 
613
                                fprintf(stderr, "%d / %d (%.2f%%)\t\t",
 
614
                                                AG(cache_stats)[i+j][1], AG(cache_stats)[i+j][0]+AG(cache_stats)[i+j][1],
 
615
                                                ((double) AG(cache_stats)[i+j][1] / (AG(cache_stats)[i+j][0]+AG(cache_stats)[i+j][1]))*100);
 
616
                        }
 
617
                        fprintf(stderr, "\n");
 
618
                }
 
619
                                        
 
620
        } while (0);
 
621
#endif
 
622
 
 
623
#endif
 
624
 
 
625
#if defined(ZEND_MM) && ZEND_DEBUG
 
626
        zend_mm_shutdown(&AG(mm_heap));
 
627
        if (full_shutdown) {
 
628
                return;
 
629
        }
 
630
        zend_mm_startup(&AG(mm_heap), 256*1024);
 
631
#elif defined(ZEND_WIN32) && ZEND_DEBUG
 
632
        if (full_shutdown && AG(memory_heap)) {
 
633
                HeapDestroy(AG(memory_heap));
 
634
                return;
 
635
        }
 
636
#endif
 
637
}
 
638
 
 
639
 
 
640
#if ZEND_DEBUG
 
641
void zend_debug_alloc_output(char *format, ...)
 
642
{
 
643
        char output_buf[256];
 
644
        va_list args;
 
645
 
 
646
        va_start(args, format);
 
647
        vsprintf(output_buf, format, args);
 
648
        va_end(args);
 
649
 
 
650
#ifdef ZEND_WIN32
 
651
        OutputDebugString(output_buf);
 
652
#else
 
653
        fprintf(stderr, "%s", output_buf);
 
654
#endif
 
655
}
 
656
 
 
657
 
 
658
ZEND_API int _mem_block_check(void *ptr, int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
 
659
{
 
660
        zend_mem_header *p = (zend_mem_header *) ((char *)ptr - sizeof(zend_mem_header) - MEM_HEADER_PADDING);
 
661
        int no_cache_notice=0;
 
662
        int valid_beginning=1;
 
663
        int had_problems=0;
 
664
        long end_magic;
 
665
 
 
666
        if (silent==2) {
 
667
                silent = 1;
 
668
                no_cache_notice = 1;
 
669
        }
 
670
        if (silent==3) {
 
671
                silent = 0;
 
672
                no_cache_notice = 1;
 
673
        }
 
674
        if (!silent) {
 
675
                zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL);
 
676
                zend_debug_alloc_output("---------------------------------------\n");
 
677
                zend_debug_alloc_output("%s(%d) : Block 0x%0.8lX status:\n" ZEND_FILE_LINE_RELAY_CC, (long) p);
 
678
                if (__zend_orig_filename) {
 
679
                        zend_debug_alloc_output("%s(%d) : Actual location (location was relayed)\n" ZEND_FILE_LINE_ORIG_RELAY_CC);
 
680
                }
 
681
                zend_debug_alloc_output("%10s\t","Beginning:  ");
 
682
        }
 
683
 
 
684
        switch (p->magic) {
 
685
                case MEM_BLOCK_START_MAGIC:
 
686
                        if (!silent) {
 
687
                                zend_debug_alloc_output("OK (allocated on %s:%d, %d bytes)\n", p->filename, p->lineno, p->size);
 
688
                        }
 
689
                        break; /* ok */
 
690
                case MEM_BLOCK_FREED_MAGIC:
 
691
                        if (!silent) {
 
692
                                zend_debug_alloc_output("Freed\n");
 
693
                                had_problems = 1;
 
694
                        } else {
 
695
                                return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
 
696
                        }
 
697
                        break;
 
698
                case MEM_BLOCK_CACHED_MAGIC:
 
699
                        if (!silent) {
 
700
                                if (!no_cache_notice) {
 
701
                                        zend_debug_alloc_output("Cached (allocated on %s:%d, %d bytes)\n", p->filename, p->lineno, p->size);
 
702
                                        had_problems = 1;
 
703
                                }
 
704
                        } else {
 
705
                                if (!no_cache_notice) {
 
706
                                        return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
 
707
                                }
 
708
                        }
 
709
                        break;
 
710
                default:
 
711
                        if (!silent) {
 
712
                                zend_debug_alloc_output("Overrun (magic=0x%0.8lX, expected=0x%0.8lX)\n", p->magic, MEM_BLOCK_START_MAGIC);
 
713
                        } else {
 
714
                                return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
 
715
                        }
 
716
                        had_problems = 1;
 
717
                        valid_beginning = 0;
 
718
                        break;
 
719
        }
 
720
 
 
721
 
 
722
        memcpy(&end_magic, (((char *) p)+sizeof(zend_mem_header)+MEM_HEADER_PADDING+p->size), sizeof(long));
 
723
 
 
724
        if (valid_beginning && (end_magic != MEM_BLOCK_END_MAGIC)) {
 
725
                char *overflow_ptr, *magic_ptr=(char *) &mem_block_end_magic;
 
726
                int overflows=0;
 
727
                long i;
 
728
 
 
729
                if (silent) {
 
730
                        return _mem_block_check(ptr, 0 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
 
731
                }
 
732
                had_problems = 1;
 
733
                overflow_ptr = (char *) &end_magic;
 
734
 
 
735
                for (i=0; i<(int)sizeof(long); i++) {
 
736
                        if (overflow_ptr[i]!=magic_ptr[i]) {
 
737
                                overflows++;
 
738
                        }
 
739
                }
 
740
 
 
741
                zend_debug_alloc_output("%10s\t", "End:");
 
742
                zend_debug_alloc_output("Overflown (magic=0x%0.8lX instead of 0x%0.8lX)\n", end_magic, MEM_BLOCK_END_MAGIC);
 
743
                zend_debug_alloc_output("%10s\t","");
 
744
                if (overflows>=(int)sizeof(long)) {
 
745
                        zend_debug_alloc_output("At least %d bytes overflown\n", sizeof(long));
 
746
                } else {
 
747
                        zend_debug_alloc_output("%d byte(s) overflown\n", overflows);
 
748
                }
 
749
        } else if (!silent) {
 
750
                zend_debug_alloc_output("%10s\t", "End:");
 
751
                if (valid_beginning) {
 
752
                        zend_debug_alloc_output("OK\n");
 
753
                } else {
 
754
                        zend_debug_alloc_output("Unknown\n");
 
755
                }
 
756
        }
 
757
                
 
758
        if (!silent) {
 
759
                zend_debug_alloc_output("---------------------------------------\n");
 
760
        }
 
761
        return ((!had_problems) ? 1 : 0);
 
762
}
 
763
 
 
764
 
 
765
ZEND_API void _full_mem_check(int silent ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
 
766
{
 
767
        zend_mem_header *p;
 
768
        int errors=0;
 
769
        TSRMLS_FETCH();
 
770
 
 
771
        p = AG(head);
 
772
        
 
773
 
 
774
        zend_debug_alloc_output("------------------------------------------------\n");
 
775
        zend_debug_alloc_output("Full Memory Check at %s:%d\n" ZEND_FILE_LINE_RELAY_CC);
 
776
 
 
777
        while (p) {
 
778
                if (!_mem_block_check((void *)((char *)p + sizeof(zend_mem_header) + MEM_HEADER_PADDING), (silent?2:3) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC)) {
 
779
                        errors++;
 
780
                }
 
781
                p = p->pNext;
 
782
        }
 
783
        zend_debug_alloc_output("End of full memory check %s:%d (%d errors)\n" ZEND_FILE_LINE_RELAY_CC, errors);
 
784
        zend_debug_alloc_output("------------------------------------------------\n");
 
785
}
 
786
#endif
 
787
 
 
788
 
 
789
/*
 
790
 * Local variables:
 
791
 * tab-width: 4
 
792
 * c-basic-offset: 4
 
793
 * indent-tabs-mode: t
 
794
 * End:
 
795
 */