From a3a46c21f0deb2840efed3780329418c0448ef66 Mon Sep 17 00:00:00 2001 From: FlavioJS Date: Wed, 13 Feb 2008 18:05:56 +0000 Subject: * Changes to memory manager: [FlavioJS] - fixed blocks that are fully used not being detected (and not freed) in memmgr_final (unfill_prev is NULL for unused blocks and full blocks) - fixed memmgr_final giving the wrong address to _mfree (for small blocks) - added the pointer address to most error messages (and log) - made it append to the log file instead of rewriting it - implemented a function to verify if a memory location is active - other minor changes git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12200 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 10 ++++- src/common/malloc.c | 114 ++++++++++++++++++++++++++++++++++++++-------------- src/common/malloc.h | 1 + 3 files changed, 93 insertions(+), 32 deletions(-) diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index e1872693e..4fa49f97a 100644 --- a/Changelog-Trunk.txt +++ b/Changelog-Trunk.txt @@ -4,7 +4,15 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK. 2008/02/13 - * Merged memory manager updates from old jA revisions (bugreport:663) + * Changes to memory manager: [FlavioJS] + - fixed blocks that are fully used not being detected (and not freed) in + memmgr_final (unfill_prev is NULL for unused blocks and full blocks) + - fixed memmgr_final giving the wrong address to _mfree (for small blocks) + - added the pointer address to most error messages (and log) + - made it append to the log file instead of rewriting it + - implemented a function to verify if a memory location is active + - other minor changes + * Merged memory manager updates from old jA revisions (bugreport:663) [ultramage] - less overhead and better overflow detection (caution, experimental!) * Added some security checks in mail system [Zephyrus] - This supose to fix a bug reported in 622 to limit to MAX_ZENY. diff --git a/src/common/malloc.c b/src/common/malloc.c index 88d43b21e..90efd04ee 100644 --- a/src/common/malloc.c +++ b/src/common/malloc.c @@ -376,7 +376,7 @@ void _mfree(void *ptr, const char *file, int line, const char *func ) *(long*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size) != 0xdeadbeaf) { - ShowError("Memory manager: args of aFree is overflowed pointer %s line %d\n", file, line); + ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); } else { head->size = -1; if(head_large->prev) { @@ -398,11 +398,11 @@ void _mfree(void *ptr, const char *file, int line, const char *func ) /* ユニット解放 */ struct block *block = head->block; if( (char*)head - (char*)block > sizeof(struct block) ) { - ShowError("Memory manager: args of aFree is invalid pointer %s line %d\n",file,line); + ShowError("Memory manager: args of aFree 0x%p is invalid pointer %s line %d\n", ptr, file, line); } else if(head->block == NULL) { - ShowError("Memory manager: args of aFree is freed pointer %s:%d@%s\n", file, line, func); + ShowError("Memory manager: args of aFree 0x%p is freed pointer %s:%d@%s\n", ptr, file, line, func); } else if(*(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + head->size) != 0xdeadbeaf) { - ShowError("Memory manager: args of aFree is overflowed pointer %s line %d\n", file, line); + ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line); } else { memmgr_usage_bytes -= head->size; head->block = NULL; @@ -443,7 +443,7 @@ static struct block* block_malloc(unsigned short hash) hash_unfill[0] = hash_unfill[0]->unfill_next; } else { /* ブロック用の領域を新たに確保する */ - p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), file,line,func ); + p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__ ); if(p == NULL) { ShowFatalError("Memory manager::block_alloc failed.\n"); exit(EXIT_FAILURE); @@ -464,6 +464,7 @@ static struct block* block_malloc(unsigned short hash) p[i].unfill_next = hash_unfill[0]; hash_unfill[0] = &p[i]; p[i].unfill_prev = NULL; + p[i].unit_used = 0; } if(i != BLOCK_ALLOC -1) { p[i].block_next = &p[i+1]; @@ -517,20 +518,69 @@ static FILE *log_fp; static void memmgr_log (char *buf) { - time_t raw; - struct tm* t; if( !log_fp ) { - log_fp = fopen(memmer_logfile,"w"); + time_t raw; + struct tm* t; + + log_fp = fopen(memmer_logfile,"at"); if (!log_fp) log_fp = stdout; - fprintf(log_fp, "Memory manager: Memory leaks found (Revision %s).\n", get_svn_revision()); + + time(&raw); + t = localtime(&raw); + fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (Revision %s).\n", + (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, get_svn_revision()); } - time(&raw); - t = localtime(&raw); - fprintf(log_fp, "%04d%02d%02d%02d%02d%02d %s", (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, buf); + fprintf(log_fp, "%s", buf); return; } -#endif +#endif /* LOG_MEMMGR */ + +/// Returns true if the memory location is active. +/// Active means it is allocated and points to a usable part. +/// +/// @param ptr Pointer to the memory +/// @return true if the memory is active +bool memmgr_verify(void* ptr) +{ + struct block* block = block_first; + struct unit_head_large* large = unit_head_large_first; + + if( ptr == NULL ) + return false;// never valid + + // search small blocks + while( block ) + { + if( (char*)ptr >= (char*)block && (char*)ptr < ((char*)block) + sizeof(struct block) ) + {// found memory block + if( block->unit_used && (char*)ptr >= block->data ) + {// memory block is being used and ptr points to a sub-unit + size_t i = (size_t)((char*)ptr - block->data)/block->unit_size; + struct unit_head* head = block2unit(block, i); + if( i < block->unit_maxused && head->block != NULL ) + {// memory unit is allocated, check if ptr points to the usable part + return ( (char*)ptr >= ((char*)head) + sizeof(struct unit_head) - sizeof(long) + && (char*)ptr < ((char*)head) + sizeof(struct unit_head) - sizeof(long) + head->size ); + } + } + return false; + } + block = block->block_next; + } + + // search large blocks + while( large ) + { + if( (char*)ptr >= (char*)large && (char*)ptr < ((char*)large) + large->size ) + {// found memory block, check if ptr points to the usable part + return ( (char*)ptr >= ((char*)large) + sizeof(struct unit_head_large) - sizeof(long) + && (char*)ptr < ((char*)large) + sizeof(struct unit_head_large) - sizeof(long) + large->size ); + } + large = large->next; + } + return false; +} static void memmgr_final (void) { @@ -539,23 +589,24 @@ static void memmgr_final (void) #ifdef LOG_MEMMGR int count = 0; -#endif - +#endif /* LOG_MEMMGR */ + while (block) { - if (block->unfill_prev) { + if (block->unit_used) { int i; for (i = 0; i < block->unit_maxused; i++) { struct unit_head *head = block2unit(block, i); if(head->block != NULL) { + char* ptr = (char *)head + sizeof(struct unit_head) - sizeof(long); #ifdef LOG_MEMMGR - char buf[128]; + char buf[1024]; sprintf (buf, - "%04d : %s line %d size %lu\n", ++count, - head->file, head->line, (unsigned long)head->size); + "%04d : %s line %d size %lu address 0x%p\n", ++count, + head->file, head->line, (unsigned long)head->size, ptr); memmgr_log (buf); -#endif +#endif /* LOG_MEMMGR */ // get block pointer and free it [celest] - _mfree ((char *)head + sizeof(struct unit_head) - sizeof(short), ALC_MARK); + _mfree(ptr, ALC_MARK); } } } @@ -565,12 +616,12 @@ static void memmgr_final (void) while(large) { struct unit_head_large *large2; #ifdef LOG_MEMMGR - char buf[128]; + char buf[1024]; sprintf (buf, - "%04d : %s line %d size %lu\n", ++count, - large->unit_head.file, large->unit_head.line, (unsigned long)large->unit_head.size); + "%04d : %s line %d size %lu address 0x%p\n", ++count, + large->unit_head.file, large->unit_head.line, (unsigned long)large->size, &large->unit_head.checksum); memmgr_log (buf); -#endif +#endif /* LOG_MEMMGR */ large2 = large->next; FREE(large,file,line,func); large = large2; @@ -582,7 +633,7 @@ static void memmgr_final (void) ShowWarning("Memory manager: Memory leaks found and fixed.\n"); fclose(log_fp); } -#endif +#endif /* LOG_MEMMGR */ return; } @@ -591,10 +642,11 @@ static void memmgr_init (void) #ifdef LOG_MEMMGR sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME); ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile); -#endif + memset(hash_unfill, 0, sizeof(hash_unfill)); +#endif /* LOG_MEMMGR */ return; } -#endif +#endif /* USE_MEMMGR */ /*====================================== @@ -605,10 +657,10 @@ static void memmgr_init (void) bool malloc_verify(void* ptr) { #ifdef USE_MEMMGR - -#endif - + return memmgr_verify(ptr); +#else return true; +#endif } unsigned int malloc_usage (void) diff --git a/src/common/malloc.h b/src/common/malloc.h index 1efc4686f..609f0a700 100644 --- a/src/common/malloc.h +++ b/src/common/malloc.h @@ -155,6 +155,7 @@ //////////////////////////////////////////////// +bool malloc_verify(void* ptr); unsigned int malloc_usage (void); void malloc_init (void); void malloc_final (void); -- cgit v1.2.3-70-g09d2