diff options
Diffstat (limited to 'src/kvilib/core/kvi_malloc.cpp')
-rw-r--r-- | src/kvilib/core/kvi_malloc.cpp | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/src/kvilib/core/kvi_malloc.cpp b/src/kvilib/core/kvi_malloc.cpp new file mode 100644 index 00000000..9c418ec5 --- /dev/null +++ b/src/kvilib/core/kvi_malloc.cpp @@ -0,0 +1,198 @@ +//============================================================================= +// +// File : kvi_malloc.cpp +// Creation date : Sun Jun 18 2000 18:26:27 CEST by Szymon Stefanek +// +// This file is part of the KVirc irc client distribution +// Copyright (C) 1999-2006 Szymon Stefanek (pragma at kvirc dot net) +// +// This program is FREE software. You can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your opinion) any later version. +// +// This program is distributed in the HOPE that it will be USEFUL, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// See the GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, write to the Free Software Foundation, +// Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +//============================================================================= + +//============================================================================= +// C memory allocation routines +// This stuff is rather unused, because in normal compilations +// kvi_malloc , kvi_free and kvi_realloc are macros (see kvi_malloc.h) +//============================================================================= + +#define __KVILIB__ + +#define _KVI_MALLOC_CPP_ +#include "kvi_malloc.h" + +#include <stdio.h> + + + +#ifdef COMPILE_MEMORY_PROFILE + + // + // Memory profile stuff + // Used to find memory leaks etc... + // + + #include "kvi_pointerlist.h" + + typedef struct _KviMallocEntry { + struct _KviMallocEntry * prev; + void * pointer; + int size; + void * return_addr1; + void * return_addr2; + struct _KviMallocEntry * next; + } KviMallocEntry; + + int g_iMaxRequestSize = 0; + void * g_pMaxRequestReturnAddress1 = 0; + void * g_pMaxRequestReturnAddress2 = 0; + unsigned int g_iMallocCalls = 0; + unsigned int g_iReallocCalls = 0; + unsigned int g_iFreeCalls = 0; + unsigned int g_iTotalMemAllocated = 0; + unsigned int g_uAllocationPeak = 0; + KviMallocEntry * g_pEntries = 0; + + void * kvi_malloc(int size) + { + g_iMallocCalls ++; + g_iTotalMemAllocated += size; + if(g_iTotalMemAllocated > g_uAllocationPeak)g_uAllocationPeak = g_iTotalMemAllocated; + if(g_iMaxRequestSize < size){ + g_iMaxRequestSize = size; + g_pMaxRequestReturnAddress1 = __builtin_return_address(1); + g_pMaxRequestReturnAddress2 = __builtin_return_address(2); + } + KviMallocEntry * e = (KviMallocEntry *)malloc(sizeof(KviMallocEntry)); + e->pointer = malloc(size); + e->size = size; + e->return_addr1 = __builtin_return_address(1); + e->return_addr2 = __builtin_return_address(2); + e->next = g_pEntries; + e->prev = 0; + if(g_pEntries)g_pEntries->prev = e; + g_pEntries = e; + return e->pointer; + } + + void * kvi_realloc(void * ptr,int size) + { + g_iReallocCalls ++; + if(ptr == 0)return kvi_malloc(size); + if(g_iMaxRequestSize < size){ + g_iMaxRequestSize = size; + g_pMaxRequestReturnAddress1 = __builtin_return_address(1); + g_pMaxRequestReturnAddress2 = __builtin_return_address(2); + } + KviMallocEntry *e = g_pEntries; + while(e){ + if(e->pointer == ptr){ + g_iTotalMemAllocated -= e->size; + g_iTotalMemAllocated += size; + if(g_iTotalMemAllocated > g_uAllocationPeak)g_uAllocationPeak = g_iTotalMemAllocated; + e->pointer = realloc(ptr,size); + e->size = size; + e->return_addr1 = __builtin_return_address(1); + e->return_addr2 = __builtin_return_address(2); + return e->pointer; + } + e = e->next; + } + fprintf(stderr,"Attempt to realloc an inexisting pointer (%p) (called from %p (%p))\n",ptr,__builtin_return_address(1),__builtin_return_address(2)); + return realloc(ptr,size); + } + + void kvi_free(void * ptr) + { + g_iFreeCalls++; + if(ptr == 0){ + fprintf(stderr,"Attempt to free a null pointer (called from %p (%p))\n",__builtin_return_address(1),__builtin_return_address(2)); + exit(-1); + } + KviMallocEntry * e= g_pEntries; + while(e){ + if(e->pointer == ptr){ + g_iTotalMemAllocated -= e->size; + if(e->prev){ + if(e == g_pEntries)fprintf(stderr,"Mem profiling internal error!\n"); + e->prev->next = e->next; + if(e->next)e->next->prev = e->prev; + } else { + if(e != g_pEntries)fprintf(stderr,"Mem profiling internal error!\n"); + if(e->next)e->next->prev = 0; + g_pEntries = e->next; + } + free(e); + return; + } + e = e->next; + } + fprintf(stderr,"Attempt to free an inexisting pointer (%p) (called from %p (%p))\n",ptr,__builtin_return_address(1),__builtin_return_address(2)); + } + + void kvi_memory_profile() __attribute__((destructor)); + void kvi_memory_profile() + { + unsigned int countUnfreed = 0; + KviMallocEntry * e = g_pEntries; + while(e){ + countUnfreed++; + e = e->next; + } + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Memory profile for KVIrc\n"); + fprintf(stderr,"| Unfreed chunks : %d\n",countUnfreed); + fprintf(stderr,"| Total unfreed memory : %u bytes\n",g_iTotalMemAllocated); + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Possible unfreed chunks dump:\n"); + e = g_pEntries; + while(e){ + fprintf(stderr,"|====|====|\n"); + fprintf(stderr,"| Currently unfreed chunk: %p\n",e->pointer); + fprintf(stderr,"| Size: %d\n",e->size); + fprintf(stderr,"| Caller address 1: %p\n",e->return_addr1); + fprintf(stderr,"| Caller address 2: %p\n",e->return_addr2); + if(e->size > 10)fprintf(stderr,"| Data: %.10s\n",e->pointer); + else if(e->size > 5)fprintf(stderr,"| Data: %.5s\n",e->pointer); + KviMallocEntry *toFree = e; + e = e->next; + free(toFree); + } + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Allocation peak : %u bytes\n",g_uAllocationPeak); + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Max request size : %d bytes\n",g_iMaxRequestSize); + fprintf(stderr,"| Called from %p (%p)\n",g_pMaxRequestReturnAddress1,g_pMaxRequestReturnAddress2); + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + fprintf(stderr,"| Malloc calls: %u\n",g_iMallocCalls); + fprintf(stderr,"| Realloc calls: %u\n",g_iReallocCalls); + fprintf(stderr,"| Free calls: %u\n",g_iFreeCalls); + fprintf(stderr,"|====|====|====|====|====|====|====|====\n"); + } + +#else + + #ifdef COMPILE_MEMORY_CHECKS + + void outOfMemory() + { + //What a cool message :) + fprintf(stderr,"Virtual memory exhausted in malloc call....bye!\n"); + exit(-1); + } + + #endif + +#endif |