summaryrefslogtreecommitdiff
path: root/Zend/zend_alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_alloc.c')
-rw-r--r--Zend/zend_alloc.c498
1 files changed, 498 insertions, 0 deletions
diff --git a/Zend/zend_alloc.c b/Zend/zend_alloc.c
new file mode 100644
index 0000000000..0336982a07
--- /dev/null
+++ b/Zend/zend_alloc.c
@@ -0,0 +1,498 @@
+/*
+ +----------------------------------------------------------------------+
+ | Zend Engine |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1998, 1999 Andi Gutmans, Zeev Suraski |
+ +----------------------------------------------------------------------+
+ | This source file is subject to the Zend license, that is bundled |
+ | with this package in the file LICENSE. If you did not receive a |
+ | copy of the Zend license, please mail us at zend@zend.com so we can |
+ | send you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Andi Gutmans <andi@zend.com> |
+ | Zeev Suraski <zeev@zend.com> |
+ +----------------------------------------------------------------------+
+*/
+
+#include <stdlib.h>
+
+#include "zend.h"
+#include "zend_alloc.h"
+#include "zend_globals.h"
+
+#ifndef ZTS
+static zend_alloc_globals alloc_globals;
+#endif
+
+
+#if ZEND_DEBUG
+# define END_MAGIC_SIZE sizeof(long)
+# define END_ALIGNMENT(size) (((size)%PLATFORM_ALIGNMENT)?(PLATFORM_ALIGNMENT-((size)%PLATFORM_ALIGNMENT)):0)
+#else
+# define END_MAGIC_SIZE 0
+# define END_ALIGNMENT(size) 0
+#endif
+
+
+# if MEMORY_LIMIT
+# if ZEND_DEBUG
+#define CHECK_MEMORY_LIMIT(s) _CHECK_MEMORY_LIMIT(s,filename,lineno)
+# else
+#define CHECK_MEMORY_LIMIT(s) _CHECK_MEMORY_LIMIT(s,NULL,0)
+# endif
+
+#define _CHECK_MEMORY_LIMIT(s,file,lineno) { AG(allocated_memory) += (s);\
+ if (php3_ini.memory_limit<AG(allocated_memory)) {\
+ if (!file) { \
+ zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted (tried to allocate %d bytes)",php3_ini.memory_limit,s); \
+ } else { \
+ zend_error(E_ERROR,"Allowed memory size of %d bytes exhausted at %s:%d (tried to allocate %d bytes)",php3_ini.memory_limit,file,lineno,s); \
+ } \
+ } \
+ }
+# endif
+
+#ifndef CHECK_MEMORY_LIMIT
+#define CHECK_MEMORY_LIMIT(s)
+#endif
+
+
+#define REMOVE_POINTER_FROM_LIST(p) \
+ if (!p->persistent && p==AG(head)) { \
+ AG(head) = p->pNext; \
+ } else if (p->persistent && p==AG(phead)) { \
+ AG(phead) = p->pNext; \
+ } else { \
+ p->pLast->pNext = p->pNext; \
+ } \
+ if (p->pNext) { \
+ p->pNext->pLast = p->pLast; \
+ }
+
+#define ADD_POINTER_TO_LIST(p) \
+ if (p->persistent) { \
+ p->pNext = AG(phead); \
+ if (AG(phead)) { \
+ AG(phead)->pLast = p; \
+ } \
+ AG(phead) = p; \
+ } else { \
+ p->pNext = AG(head); \
+ if (AG(head)) { \
+ AG(head)->pLast = p; \
+ } \
+ AG(head) = p; \
+ } \
+ p->pLast = (mem_header *) NULL;
+
+
+/* used by ISAPI and NSAPI */
+
+#if ZEND_DEBUG
+ZEND_API void *_emalloc(size_t size, char *filename, uint lineno)
+#else
+ZEND_API void *_emalloc(size_t size)
+#endif
+{
+ mem_header *p;
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+
+ if ((size < MAX_CACHED_MEMORY) && (AG(cache_count)[size] > 0)) {
+ p = AG(cache)[size][--AG(cache_count)[size]];
+#if ZEND_DEBUG
+ p->filename = filename;
+ p->lineno = lineno;
+ p->magic = MEM_BLOCK_START_MAGIC;
+#endif
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ p->persistent = 0;
+ p->cached = 0;
+ return (void *)((char *)p + sizeof(mem_header) + PLATFORM_PADDING);
+ } else {
+ p = (mem_header *) malloc(sizeof(mem_header) + size + PLATFORM_PADDING + END_ALIGNMENT(size) + END_MAGIC_SIZE);
+ }
+
+ if (!p) {
+ fprintf(stderr,"FATAL: emalloc(): Unable to allocate %d bytes\n", size);
+ exit(1);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return (void *)p;
+ }
+ p->persistent = p->cached = 0;
+ ADD_POINTER_TO_LIST(p);
+ p->size = size;
+#if ZEND_DEBUG
+ p->filename = filename;
+ p->lineno = lineno;
+ p->magic = MEM_BLOCK_START_MAGIC;
+ *((long *)(((char *) p) + sizeof(mem_header)+size+PLATFORM_PADDING+END_ALIGNMENT(size))) = MEM_BLOCK_END_MAGIC;
+#endif
+#if MEMORY_LIMIT
+ CHECK_MEMORY_LIMIT(size);
+#endif
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return (void *)((char *)p + sizeof(mem_header) + PLATFORM_PADDING);
+}
+
+
+#if ZEND_DEBUG
+ZEND_API void _efree(void *ptr, char *filename, uint lineno)
+#else
+ZEND_API void _efree(void *ptr)
+#endif
+{
+ mem_header *p = (mem_header *) ((char *)ptr - sizeof(mem_header) - PLATFORM_PADDING);
+
+#if ZEND_DEBUG
+ _mem_block_check(ptr, 1, filename, lineno);
+ memset(ptr, 0x5a, p->size);
+#endif
+
+ if (!p->persistent && (p->size < MAX_CACHED_MEMORY) && (AG(cache_count)[p->size] < MAX_CACHED_ENTRIES)) {
+ AG(cache)[p->size][AG(cache_count)[p->size]++] = p;
+ p->cached = 1;
+#if ZEND_DEBUG
+ p->magic = MEM_BLOCK_CACHED_MAGIC;
+#endif
+ return;
+ }
+ HANDLE_BLOCK_INTERRUPTIONS();
+ REMOVE_POINTER_FROM_LIST(p);
+
+#if MEMORY_LIMIT
+ AG(allocated_memory) -= p->size;
+#endif
+
+ free(p);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+}
+
+
+#if ZEND_DEBUG
+ZEND_API void *_ecalloc(size_t nmemb, size_t size, char *filename, uint lineno)
+#else
+ZEND_API void *_ecalloc(size_t nmemb, size_t size)
+#endif
+{
+ void *p;
+ int final_size=size*nmemb;
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+#if ZEND_DEBUG
+ p = _emalloc(final_size,filename,lineno);
+#else
+ p = emalloc(final_size);
+#endif
+ if (!p) {
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return (void *) p;
+ }
+ memset(p,(int)NULL,final_size);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return p;
+}
+
+
+#if ZEND_DEBUG
+ZEND_API void *_erealloc(void *ptr, size_t size, char *filename, uint lineno)
+#else
+ZEND_API void *_erealloc(void *ptr, size_t size)
+#endif
+{
+ mem_header *p = (mem_header *) ((char *)ptr-sizeof(mem_header)-PLATFORM_PADDING);
+ mem_header *orig = p;
+
+ if (!ptr) {
+#if ZEND_DEBUG
+ return _emalloc(size, filename, lineno);
+#else
+ return emalloc(size);
+#endif
+ }
+ HANDLE_BLOCK_INTERRUPTIONS();
+ REMOVE_POINTER_FROM_LIST(p);
+ p = (mem_header *) realloc(p,sizeof(mem_header)+size+PLATFORM_PADDING+END_ALIGNMENT(size)+END_MAGIC_SIZE);
+ if (!p) {
+ fprintf(stderr,"FATAL: erealloc(): Unable to allocate %d bytes\n", size);
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ zend_bailout();
+ ADD_POINTER_TO_LIST(orig);
+ return (void *)NULL;
+ }
+ ADD_POINTER_TO_LIST(p);
+#if ZEND_DEBUG
+ p->filename = filename;
+ p->lineno = lineno;
+ p->magic = MEM_BLOCK_START_MAGIC;
+ *((long *)(((char *) p) + sizeof(mem_header)+size+PLATFORM_PADDING+END_ALIGNMENT(size))) = MEM_BLOCK_END_MAGIC;
+#endif
+#if MEMORY_LIMIT
+ CHECK_MEMORY_LIMIT(size - p->size);
+#endif
+ p->size = size;
+
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return (void *)((char *)p+sizeof(mem_header)+PLATFORM_PADDING);
+}
+
+
+#if ZEND_DEBUG
+ZEND_API char *_estrdup(const char *s, char *filename, uint lineno)
+#else
+ZEND_API char *_estrdup(const char *s)
+#endif
+{
+ int length;
+ char *p;
+
+ length = strlen(s)+1;
+ HANDLE_BLOCK_INTERRUPTIONS();
+#if ZEND_DEBUG
+ p = (char *) _emalloc(length,filename,lineno);
+#else
+ p = (char *) emalloc(length);
+#endif
+ if (!p) {
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return (char *)NULL;
+ }
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ memcpy(p,s,length);
+ return p;
+}
+
+
+#if ZEND_DEBUG
+ZEND_API char *_estrndup(const char *s, uint length, char *filename, uint lineno)
+#else
+ZEND_API char *_estrndup(const char *s, uint length)
+#endif
+{
+ char *p;
+
+ HANDLE_BLOCK_INTERRUPTIONS();
+#if ZEND_DEBUG
+ p = (char *) _emalloc(length+1,filename,lineno);
+#else
+ p = (char *) emalloc(length+1);
+#endif
+ if (!p) {
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ return (char *)NULL;
+ }
+ HANDLE_UNBLOCK_INTERRUPTIONS();
+ memcpy(p,s,length);
+ p[length]=0;
+ return p;
+}
+
+
+ZEND_API char *zend_strndup(const char *s, uint length)
+{
+ char *p;
+
+ p = (char *) malloc(length+1);
+ if (!p) {
+ return (char *)NULL;
+ }
+ if (length) {
+ memcpy(p,s,length);
+ }
+ p[length]=0;
+ return p;
+}
+
+
+ZEND_API void start_memory_manager(void)
+{
+ AG(phead) = AG(head) = NULL;
+
+#if MEMORY_LIMIT
+ AG(allocated_memory)=0;
+ AG(memory_exhausted)=0;
+#endif
+
+ memset(AG(cache_count),0,MAX_CACHED_MEMORY*sizeof(unsigned char));
+}
+
+
+ZEND_API void shutdown_memory_manager(int silent, int clean_cache)
+{
+ mem_header *p, *t;
+
+ p=AG(head);
+ t=AG(head);
+ while (t) {
+ if (!t->cached || clean_cache) {
+#if ZEND_DEBUG
+ if (!t->cached) {
+ /* does not use zend_error() *intentionally* */
+ if (!silent) {
+ zend_message_dispatcher(ZMSG_MEMORY_LEAK_DETECTED, t);
+ }
+ }
+#endif
+ p = t->pNext;
+ REMOVE_POINTER_FROM_LIST(t);
+ free(t);
+ t = p;
+ } else {
+ t = t->pNext;
+ }
+ }
+}
+
+
+#if ZEND_DEBUG
+ZEND_API int _mem_block_check(void *ptr, int silent, char *filename, int lineno)
+{
+ mem_header *p = (mem_header *) ((char *)ptr - sizeof(mem_header) - PLATFORM_PADDING);
+ int no_cache_notice=0;
+ int valid_beginning=1;
+ int had_problems=0;
+
+ if (silent==2) {
+ silent=1;
+ no_cache_notice=1;
+ }
+ if (silent==3) {
+ silent=0;
+ no_cache_notice=1;
+ }
+ if (!silent) {
+ fprintf(stderr,"---------------------------------------\n");
+ fprintf(stderr,"Block 0x%0.8lX status at %s:%d:\n", (long) p, filename, lineno);
+ fprintf(stderr,"%10s\t","Beginning: ");
+ }
+
+ switch (p->magic) {
+ case MEM_BLOCK_START_MAGIC:
+ if (!silent) {
+ fprintf(stderr, "OK (allocated on %s:%d, %d bytes)\n", p->filename, p->lineno, p->size);
+ }
+ break; /* ok */
+ case MEM_BLOCK_FREED_MAGIC:
+ if (!silent) {
+ fprintf(stderr,"Freed\n");
+ had_problems=1;
+ } else {
+ return _mem_block_check(ptr, 0, filename, lineno);
+ }
+ break;
+ case MEM_BLOCK_CACHED_MAGIC:
+ if (!silent) {
+ if (!no_cache_notice) {
+ fprintf(stderr,"Cached (allocated on %s:%d, %d bytes)\n", p->filename, p->lineno, p->size);
+ had_problems=1;
+ }
+ } else {
+ if (!no_cache_notice) {
+ return _mem_block_check(ptr, 0, filename, lineno);
+ }
+ }
+ break;
+ default:
+ if (!silent) {
+ fprintf(stderr,"Overrun (magic=0x%0.8lX, expected=0x%0.8lX)\n", p->magic, MEM_BLOCK_START_MAGIC);
+ } else {
+ return _mem_block_check(ptr, 0, filename, lineno);
+ }
+ had_problems=1;
+ valid_beginning=0;
+ break;
+ }
+
+
+ if (valid_beginning
+ && *((long *)(((char *) p)+sizeof(mem_header)+p->size+PLATFORM_PADDING+END_ALIGNMENT(p->size))) != MEM_BLOCK_END_MAGIC) {
+ long magic_num = MEM_BLOCK_END_MAGIC;
+ char *overflow_ptr, *magic_ptr=(char *) &magic_num;
+ int overflows=0;
+ int i;
+
+ if (silent) {
+ return _mem_block_check(ptr, 0, filename, lineno);
+ }
+ had_problems=1;
+ overflow_ptr = ((char *) p)+sizeof(mem_header)+p->size+PLATFORM_PADDING;
+
+ for (i=0; i<sizeof(long); i++) {
+ if (overflow_ptr[i]!=magic_ptr[i]) {
+ overflows++;
+ }
+ }
+
+ fprintf(stderr,"%10s\t", "End:");
+ fprintf(stderr,"Overflown (magic=0x%0.8lX instead of 0x%0.8lX)\n",
+ *((long *)(((char *) p) + sizeof(mem_header)+p->size+PLATFORM_PADDING+END_ALIGNMENT(p->size))), MEM_BLOCK_END_MAGIC);
+ fprintf(stderr,"%10s\t","");
+ if (overflows>=sizeof(long)) {
+ fprintf(stderr, "At least %d bytes overflown\n", sizeof(long));
+ } else {
+ fprintf(stderr, "%d byte(s) overflown\n", overflows);
+ }
+ } else if (!silent) {
+ fprintf(stderr,"%10s\t", "End:");
+ if (valid_beginning) {
+ fprintf(stderr,"OK\n");
+ } else {
+ fprintf(stderr,"Unknown\n");
+ }
+ }
+
+ if (!silent) {
+ fprintf(stderr,"---------------------------------------\n");
+ }
+ return ((!had_problems) ? 1 : 0);
+}
+
+
+ZEND_API void _full_mem_check(int silent, char *filename, uint lineno)
+{
+ mem_header *p = AG(head);
+ int errors=0;
+
+ fprintf(stderr,"------------------------------------------------\n");
+ fprintf(stderr,"Full Memory Check at %s:%d\n", filename, lineno);
+
+ while (p) {
+ if (!_mem_block_check((void *)((char *)p + sizeof(mem_header) + PLATFORM_PADDING), (silent?2:3), filename, lineno)) {
+ errors++;
+ }
+ p = p->pNext;
+ }
+ fprintf(stderr,"End of full memory check %s:%d (%d errors)\n", filename, lineno, errors);
+ fprintf(stderr,"------------------------------------------------\n");
+}
+#endif
+
+
+#if ZEND_DEBUG
+ZEND_API void _persist_alloc(void *ptr, char *filename, uint lineno)
+#else
+ZEND_API void _persist_alloc(void *ptr)
+#endif
+{
+ mem_header *p = (mem_header *) ((char *)ptr-sizeof(mem_header)-PLATFORM_PADDING);
+
+#if ZEND_DEBUG
+ _mem_block_check(ptr, 1, filename, lineno);
+#endif
+
+ /* remove the block from the non persistent list */
+ REMOVE_POINTER_FROM_LIST(p);
+
+ p->persistent = 1;
+
+ /* add the block to the persistent list */
+ ADD_POINTER_TO_LIST(p);
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */