//============================================================================= // // 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 #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