浏览代码

* 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://svn.code.sf.net/p/rathena/svn/trunk@12200 54d463be-8e91-2dee-dedb-b68131a5f0ec

FlavioJS 17 年之前
父节点
当前提交
e3bcc90775
共有 3 个文件被更改,包括 93 次插入32 次删除
  1. 9 1
      Changelog-Trunk.txt
  2. 83 31
      src/common/malloc.c
  3. 1 0
      src/common/malloc.h

+ 9 - 1
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.

+ 83 - 31
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)

+ 1 - 0
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);