rathena/src/common/malloc.c

707 lines
20 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
#include "../common/malloc.h"
#include "../common/core.h"
#include "../common/showmsg.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
////////////// Memory Libraries //////////////////
#if defined(MEMWATCH)
# include <string.h>
# include "memwatch.h"
# define MALLOC(n,file,line,func) mwMalloc((n),(file),(line))
# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line))
# define REALLOC(p,n,file,line,func) mwRealloc((p),(n),(file),(line))
# define STRDUP(p,file,line,func) mwStrdup((p),(file),(line))
# define FREE(p,file,line,func) mwFree((p),(file),(line))
#elif defined(DMALLOC)
# include <string.h>
# include <stdlib.h>
# include "dmalloc.h"
# define MALLOC(n,file,line,func) dmalloc_malloc((file),(line),(n),DMALLOC_FUNC_MALLOC,0,0)
# define CALLOC(m,n,file,line,func) dmalloc_malloc((file),(line),(m)*(n),DMALLOC_FUNC_CALLOC,0,0)
# define REALLOC(p,n,file,line,func) dmalloc_realloc((file),(line),(p),(n),DMALLOC_FUNC_REALLOC,0)
# define STRDUP(p,file,line,func) strdup(p)
# define FREE(p,file,line,func) free(p)
#elif defined(GCOLLECT)
# include "gc.h"
# define MALLOC(n,file,line,func) GC_MALLOC(n)
# define CALLOC(m,n,file,line,func) GC_MALLOC((m)*(n))
# define REALLOC(p,n,file,line,func) GC_REALLOC((p),(n))
# define STRDUP(p,file,line,func) _bstrdup(p)
# define FREE(p,file,line,func) GC_FREE(p)
char * _bstrdup(const char *);
#else
# define MALLOC(n,file,line,func) malloc(n)
# define CALLOC(m,n,file,line,func) calloc((m),(n))
# define REALLOC(p,n,file,line,func) realloc((p),(n))
# define STRDUP(p,file,line,func) strdup(p)
# define FREE(p,file,line,func) free(p)
#endif
void* aMalloc_(size_t size, const char *file, int line, const char *func)
{
void *ret = MALLOC(size, file, line, func);
// ShowMessage("%s:%d: in func %s: aMalloc %d\n",file,line,func,size);
if (ret == NULL){
ShowFatalError("%s:%d: in func %s: aMalloc error out of memory!\n",file,line,func);
exit(EXIT_FAILURE);
}
return ret;
}
void* aCalloc_(size_t num, size_t size, const char *file, int line, const char *func)
{
void *ret = CALLOC(num, size, file, line, func);
// ShowMessage("%s:%d: in func %s: aCalloc %d %d\n",file,line,func,num,size);
if (ret == NULL){
ShowFatalError("%s:%d: in func %s: aCalloc error out of memory!\n", file, line, func);
exit(EXIT_FAILURE);
}
return ret;
}
void* aRealloc_(void *p, size_t size, const char *file, int line, const char *func)
{
void *ret = REALLOC(p, size, file, line, func);
// ShowMessage("%s:%d: in func %s: aRealloc %p %d\n",file,line,func,p,size);
if (ret == NULL){
ShowFatalError("%s:%d: in func %s: aRealloc error out of memory!\n",file,line,func);
exit(EXIT_FAILURE);
}
return ret;
}
char* aStrdup_(const char *p, const char *file, int line, const char *func)
{
char *ret = STRDUP(p, file, line, func);
// ShowMessage("%s:%d: in func %s: aStrdup %p\n",file,line,func,p);
if (ret == NULL){
ShowFatalError("%s:%d: in func %s: aStrdup error out of memory!\n", file, line, func);
exit(EXIT_FAILURE);
}
return ret;
}
void aFree_(void *p, const char *file, int line, const char *func)
{
// ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p);
if (p)
FREE(p, file, line, func);
p = NULL;
}
#ifdef GCOLLECT
char* _bstrdup(const char *chr)
{
int len = strlen(chr);
char *ret = (char*)GC_MALLOC(len + 1);
if (ret) memcpy(ret, chr, len + 1);
return ret;
}
#endif
#ifdef USE_MEMMGR
#if defined(DEBUG)
#define DEBUG_MEMMGR
#endif
/* USE_MEMMGR */
/*
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>}<7D>l<EFBFBD>[<5B>W<EFBFBD><57>
* malloc , free <20>̏<EFBFBD><CC8F><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I<EFBFBD>ɏo<C98F><6F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD><EFBFBD><EFBFBD>́B
* <20><><EFBFBD>G<EFBFBD>ȏ<EFBFBD><C88F><EFBFBD><EFBFBD><EFBFBD><EFBFBD>s<EFBFBD><73><EFBFBD>Ă<EFBFBD><C482><EFBFBD><EFBFBD>̂ŁA<C581><EFBFBD>d<EFBFBD><64><EFBFBD>Ȃ邩<C882><E982A9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>܂<EFBFBD><DC82><EFBFBD><EFBFBD>B
*
* <20>f<EFBFBD>[<5B>^<5E>\<5C><><EFBFBD>Ȃǁi<C781><69><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ł<EFBFBD><C582><EFBFBD><EFBFBD>܂<EFBFBD><DC82><EFBFBD>^^; <20>j
* <20>E<EFBFBD><45><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>𕡐<EFBFBD><F095A190>́u<CC81>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>v<EFBFBD>ɕ<EFBFBD><C995><EFBFBD><EFBFBD>āA<C481><41><EFBFBD><EFBFBD><EFBFBD>Ƀu<C983><75><EFBFBD>b<EFBFBD>N<EFBFBD>𕡐<EFBFBD><F095A190>́u<CC81><75><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD>v
* <20>ɕ<EFBFBD><C995><EFBFBD><EFBFBD>Ă<EFBFBD><C482>܂<EFBFBD><DC82>B<EFBFBD><42><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD>̃T<CC83>C<EFBFBD>Y<EFBFBD>́A<CD81>P<EFBFBD>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>̗e<CC97>ʂ𕡐<CA82><F095A190>‚ɋϓ<C98B><CF93>z<EFBFBD><7A>
* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂ł<CC82><C582>B<EFBFBD><42><EFBFBD>Ƃ<EFBFBD><C682>΁A<CE81>P<EFBFBD><50><EFBFBD>j<EFBFBD>b<EFBFBD>g32KB<4B>̏ꍇ<CC8F>A<EFBFBD>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>P<EFBFBD>‚<EFBFBD>32Byte<74>̃<EFBFBD>
* <20>j<EFBFBD>b<EFBFBD>g<EFBFBD><67><EFBFBD>A1024<32>W<C28F>܂<EFBFBD><DC82>ďo<C48F><6F><EFBFBD>Ă<EFBFBD><C482><EFBFBD><EFBFBD><EFBFBD><EFBFBD>A64Byte<74>̃<EFBFBD><CC83>j<EFBFBD>b<EFBFBD>g<EFBFBD><67> 512<31>W<C28F>܂<EFBFBD><DC82><EFBFBD>
* <20>o<EFBFBD><6F><EFBFBD>Ă<EFBFBD><C482><EFBFBD><EFBFBD><EFBFBD>܂<EFBFBD><DC82>B<EFBFBD>ipadding,unit_head <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>j
*
* <20>E<EFBFBD>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD>m<EFBFBD>̓<EFBFBD><CD83><EFBFBD><EFBFBD>N<EFBFBD><4E><EFBFBD>X<EFBFBD>g(block_prev,block_next) <20>ł‚Ȃ<C282><C882><EFBFBD><EFBFBD>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD>T<EFBFBD>C
* <20>Y<EFBFBD><59><EFBFBD><EFBFBD><EFBFBD>ƒu<C283><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD>m<EFBFBD><6D><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>N<EFBFBD><4E><EFBFBD>X<EFBFBD>g(hash_prev,hash_nect) <20>ł‚<C582>
* <20><><EFBFBD><EFBFBD><EFBFBD>Ă<EFBFBD><C482>܂<EFBFBD><DC82>B<EFBFBD><42><EFBFBD><EFBFBD><EFBFBD>ɂ<EFBFBD><C982><EFBFBD><EFBFBD>A<EFBFBD>s<EFBFBD>v<EFBFBD>ƂȂ<C682><C882><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̍ė<CC8D><C497>p<EFBFBD><70><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>I<EFBFBD>ɍs<C98D><73><EFBFBD>܂<EFBFBD><DC82>B
*/
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>̃A<CC83><41><EFBFBD>C<EFBFBD><43><EFBFBD><EFBFBD><EFBFBD>g */
#define BLOCK_ALIGNMENT1 16
#define BLOCK_ALIGNMENT2 64
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>ɓ<EFBFBD><C993><EFBFBD><EFBFBD>f<EFBFBD>[<5B>^<5E><> */
#define BLOCK_DATA_COUNT1 128
#define BLOCK_DATA_COUNT2 608
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>̑傫<CC91><E582AB>: 16*128 + 64*576 = 40KB */
#define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 )
#define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 )
#define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 )
/* <20><><EFBFBD>x<EFBFBD>Ɋm<C98A>ۂ<EFBFBD><DB82><EFBFBD><EFBFBD>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>̐<EFBFBD><CC90>B */
#define BLOCK_ALLOC 104
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N */
struct block {
struct block* block_next; /* <20><><EFBFBD>Ɋm<C98A>ۂ<EFBFBD><DB82><EFBFBD><EFBFBD>̈<EFBFBD> */
struct block* unfill_prev; /* <20><><EFBFBD>̖<EFBFBD><CC96>܂<EFBFBD><DC82>Ă<EFBFBD><C482>Ȃ<EFBFBD><C882>̈<EFBFBD> */
struct block* unfill_next; /* <20><><EFBFBD>̖<EFBFBD><CC96>܂<EFBFBD><DC82>Ă<EFBFBD><C482>Ȃ<EFBFBD><C882>̈<EFBFBD> */
unsigned short unit_size; /* <20><><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD>̑傫<CC91><E582AB> */
unsigned short unit_hash; /* <20><><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD>̃n<CC83>b<EFBFBD>V<EFBFBD><56> */
unsigned short unit_count; /* <20><><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD>̌<CC8C> */
unsigned short unit_used; /* <20>g<EFBFBD>p<EFBFBD><70><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD><67> */
unsigned short unit_unfill; /* <20><><EFBFBD>g<EFBFBD>p<EFBFBD><70><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD>̏ꏊ */
unsigned short unit_maxused; /* <20>g<EFBFBD>p<EFBFBD><70><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD>̍ő<CC8D><C591>l */
char data[ BLOCK_DATA_SIZE ];
};
struct unit_head {
struct block *block;
const char* file;
unsigned short line;
unsigned short size;
long checksum;
};
static struct block* hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1];
static struct block* block_first, *block_last, block_head;
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>g<EFBFBD><67><EFBFBD>񂹂Ȃ<F182B982><C882>̈<EFBFBD><CC88>p<EFBFBD>̃f<CC83>[<5B>^ */
struct unit_head_large {
size_t size;
struct unit_head_large* prev;
struct unit_head_large* next;
struct unit_head unit_head;
};
static struct unit_head_large *unit_head_large_first = NULL;
static struct block* block_malloc(unsigned short hash);
static void block_free(struct block* p);
static size_t memmgr_usage_bytes;
#define block2unit(p, n) ((struct unit_head*)(&(p)->data[ p->unit_size * (n) ]))
#define memmgr_assert(v) do { if(!(v)) { ShowError("Memory manager: assertion '" #v "' failed!\n"); } } while(0)
static unsigned short size2hash( size_t size )
{
if( size <= BLOCK_DATA_SIZE1 ) {
return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1;
} else if( size <= BLOCK_DATA_SIZE ){
return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2
+ BLOCK_DATA_COUNT1;
} else {
return 0xffff; // <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD>𒴂<EFBFBD><F092B482><EFBFBD><EFBFBD><EFBFBD><EA8D87> hash <20>ɂ<EFBFBD><C982>Ȃ<EFBFBD>
}
}
static size_t hash2size( unsigned short hash )
{
if( hash <= BLOCK_DATA_COUNT1) {
return hash * BLOCK_ALIGNMENT1;
} else {
return (hash - BLOCK_DATA_COUNT1) * BLOCK_ALIGNMENT2 + BLOCK_DATA_SIZE1;
}
}
void* _mmalloc(size_t size, const char *file, int line, const char *func )
{
struct block *block;
short size_hash = size2hash( size );
struct unit_head *head;
if (((long) size) < 0) {
ShowError("_mmalloc: %d\n", size);
return NULL;
}
if(size == 0) {
return NULL;
}
memmgr_usage_bytes += size;
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD>𒴂<EFBFBD><F092B482><EFBFBD><EFBFBD>̈<EFBFBD><CC88>̊m<CC8A>ۂɂ́Amalloc() <20><><EFBFBD>p<EFBFBD><70><EFBFBD><EFBFBD> */
/* <20><><EFBFBD>̍ہAunit_head.block <20><> NULL <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ċ<EFBFBD><C48B>ʂ<EFBFBD><CA82><EFBFBD> */
if(hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func);
if(p != NULL) {
p->size = size;
p->unit_head.block = NULL;
p->unit_head.size = 0;
p->unit_head.file = file;
p->unit_head.line = line;
p->prev = NULL;
if (unit_head_large_first == NULL)
p->next = NULL;
else {
unit_head_large_first->prev = p;
p->next = unit_head_large_first;
}
unit_head_large_first = p;
*(long*)((char*)p + sizeof(struct unit_head_large) - sizeof(long) + size) = 0xdeadbeaf;
return (char *)p + sizeof(struct unit_head_large) - sizeof(long);
} else {
ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line);
exit(EXIT_FAILURE);
}
}
/* <20><><EFBFBD><EFBFBD><EFBFBD>T<EFBFBD>C<EFBFBD>Y<EFBFBD>̃u<CC83><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD>m<EFBFBD>ۂ<EFBFBD><DB82><EFBFBD><EFBFBD>Ă<EFBFBD><C482>Ȃ<EFBFBD><C882><EFBFBD><EFBFBD>A<EFBFBD>V<EFBFBD><56><EFBFBD>Ɋm<C98A>ۂ<EFBFBD><DB82><EFBFBD> */
if(hash_unfill[size_hash]) {
block = hash_unfill[size_hash];
} else {
block = block_malloc(size_hash);
}
if( block->unit_unfill == 0xFFFF ) {
// free<65>ςݗ̈悪<CC88>c<EFBFBD><63><EFBFBD>Ă<EFBFBD><C482>Ȃ<EFBFBD>
memmgr_assert(block->unit_used < block->unit_count);
memmgr_assert(block->unit_used == block->unit_maxused);
head = block2unit(block, block->unit_maxused);
block->unit_used++;
block->unit_maxused++;
} else {
head = block2unit(block, block->unit_unfill);
block->unit_unfill = head->size;
block->unit_used++;
}
if( block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) {
// <20><><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD><67><EFBFBD>g<EFBFBD><67><EFBFBD>ʂ<EFBFBD><CA82><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̂ŁAunfill<6C><6C><EFBFBD>X<EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD><EFBFBD>
if( block->unfill_prev == &block_head) {
hash_unfill[ size_hash ] = block->unfill_next;
} else {
block->unfill_prev->unfill_next = block->unfill_next;
}
if( block->unfill_next ) {
block->unfill_next->unfill_prev = block->unfill_prev;
}
block->unfill_prev = NULL;
}
#ifdef DEBUG_MEMMGR
{
size_t i, sz = hash2size( size_hash );
for( i=0; i<sz; i++ )
{
if( ((unsigned char*)head)[ sizeof(struct unit_head) - sizeof(long) + i] != 0xfd )
{
if( head->line != 0xfdfd )
{
ShowError("Memory manager: freed-data is changed. (freed in %s line %d)\n", head->file,head->line);
}
else
{
ShowError("Memory manager: not-allocated-data is changed.\n");
}
break;
}
}
memset( (char *)head + sizeof(struct unit_head) - sizeof(long), 0xcd, sz );
}
#endif
head->block = block;
head->file = file;
head->line = line;
head->size = (unsigned short)size;
*(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + size) = 0xdeadbeaf;
return (char *)head + sizeof(struct unit_head) - sizeof(long);
};
void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func )
{
void *p = _mmalloc(num * size,file,line,func);
memset(p,0,num * size);
return p;
}
void* _mrealloc(void *memblock, size_t size, const char *file, int line, const char *func )
{
size_t old_size;
if(memblock == NULL) {
return _mmalloc(size,file,line,func);
}
old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size;
if( old_size == 0 ) {
old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size;
}
if(old_size > size) {
// <20>T<EFBFBD>C<EFBFBD>Y<EFBFBD>k<EFBFBD><6B> -> <20><><EFBFBD>̂܂ܕԂ<DC95><D482>i<EFBFBD><EFBFBD><E894B2><EFBFBD>j
return memblock;
} else {
// <20>T<EFBFBD>C<EFBFBD>Y<EFBFBD>g<EFBFBD><67>
void *p = _mmalloc(size,file,line,func);
if(p != NULL) {
memcpy(p,memblock,old_size);
}
_mfree(memblock,file,line,func);
return p;
}
}
char* _mstrdup(const char *p, const char *file, int line, const char *func )
{
if(p == NULL) {
return NULL;
} else {
size_t len = strlen(p);
char *string = (char *)_mmalloc(len + 1,file,line,func);
memcpy(string,p,len+1);
return string;
}
}
void _mfree(void *ptr, const char *file, int line, const char *func )
{
struct unit_head *head;
if (ptr == NULL)
return;
head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long));
if(head->size == 0) {
/* malloc() <20>Œ<EFBFBD><C592>Ɋm<C98A>ۂ<EFBFBD><DB82><EFBFBD>̈<EFBFBD> */
struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long));
if(
*(long*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size)
!= 0xdeadbeaf)
{
ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line);
} else {
head->size = 0xFFFF;
if(head_large->prev) {
head_large->prev->next = head_large->next;
} else {
unit_head_large_first = head_large->next;
}
if(head_large->next) {
head_large->next->prev = head_large->prev;
}
memmgr_usage_bytes -= head_large->size;
#ifdef DEBUG_MEMMGR
// set freed memory to 0xfd
memset(ptr, 0xfd, head_large->size);
#endif
FREE(head_large,file,line,func);
}
} else {
/* <20><><EFBFBD>j<EFBFBD>b<EFBFBD>g<EFBFBD><67><EFBFBD><EFBFBD> */
struct block *block = head->block;
if( (char*)head - (char*)block > sizeof(struct block) ) {
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 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 0x%p is overflowed pointer %s line %d\n", ptr, file, line);
} else {
memmgr_usage_bytes -= head->size;
head->block = NULL;
#ifdef DEBUG_MEMMGR
memset(ptr, 0xfd, block->unit_size - sizeof(struct unit_head) + sizeof(long) );
head->file = file;
head->line = line;
#endif
memmgr_assert( block->unit_used > 0 );
if(--block->unit_used == 0) {
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>̉<EFBFBD><CC89><EFBFBD> */
block_free(block);
} else {
if( block->unfill_prev == NULL) {
// unfill <20><><EFBFBD>X<EFBFBD>g<EFBFBD>ɒlj<C992>
if( hash_unfill[ block->unit_hash ] ) {
hash_unfill[ block->unit_hash ]->unfill_prev = block;
}
block->unfill_prev = &block_head;
block->unfill_next = hash_unfill[ block->unit_hash ];
hash_unfill[ block->unit_hash ] = block;
}
head->size = block->unit_unfill;
block->unit_unfill = (unsigned short)(((uintptr_t)head - (uintptr_t)block->data) / block->unit_size);
}
}
}
}
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD>m<EFBFBD>ۂ<EFBFBD><DB82><EFBFBD> */
static struct block* block_malloc(unsigned short hash)
{
int i;
struct block *p;
if(hash_unfill[0] != NULL) {
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>p<EFBFBD>̗̈<CC97><CC88>͊m<CD8A>ۍς<DB8D> */
p = hash_unfill[0];
hash_unfill[0] = hash_unfill[0]->unfill_next;
} else {
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD>p<EFBFBD>̗̈<CC97><CC88><EFBFBD><EFBFBD>V<EFBFBD><56><EFBFBD>Ɋm<C98A>ۂ<EFBFBD><DB82><EFBFBD> */
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);
}
if(block_first == NULL) {
/* <20><><EFBFBD><EFBFBD><EFBFBD>m<EFBFBD><6D> */
block_first = p;
} else {
block_last->block_next = p;
}
block_last = &p[BLOCK_ALLOC - 1];
block_last->block_next = NULL;
/* <20>u<EFBFBD><75><EFBFBD>b<EFBFBD>N<EFBFBD><4E><EFBFBD>A<EFBFBD><41><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
for(i=0;i<BLOCK_ALLOC;i++) {
if(i != 0) {
// p[0] <20>͂<EFBFBD><CD82><EFBFBD><EA82A9><EFBFBD>g<EFBFBD><67><EFBFBD>̂Ń<CC82><C583><EFBFBD><EFBFBD>N<EFBFBD>ɂ͉<C982><CD89><EFBFBD><EFBFBD>Ȃ<EFBFBD>
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];
}
}
}
// unfill <20>ɒlj<C992>
memmgr_assert(hash_unfill[ hash ] == NULL);
hash_unfill[ hash ] = p;
p->unfill_prev = &block_head;
p->unfill_next = NULL;
p->unit_size = (unsigned short)(hash2size( hash ) + sizeof(struct unit_head));
p->unit_hash = hash;
p->unit_count = BLOCK_DATA_SIZE / p->unit_size;
p->unit_used = 0;
p->unit_unfill = 0xFFFF;
p->unit_maxused = 0;
#ifdef DEBUG_MEMMGR
memset( p->data, 0xfd, sizeof(p->data) );
#endif
return p;
}
static void block_free(struct block* p)
{
if( p->unfill_prev ) {
if( p->unfill_prev == &block_head) {
hash_unfill[ p->unit_hash ] = p->unfill_next;
} else {
p->unfill_prev->unfill_next = p->unfill_next;
}
if( p->unfill_next ) {
p->unfill_next->unfill_prev = p->unfill_prev;
}
p->unfill_prev = NULL;
}
p->unfill_next = hash_unfill[0];
hash_unfill[0] = p;
}
size_t memmgr_usage (void)
{
return memmgr_usage_bytes / 1024;
}
#ifdef LOG_MEMMGR
static char memmer_logfile[128];
static FILE *log_fp;
static void memmgr_log (char *buf)
{
if( !log_fp )
{
time_t raw;
struct tm* t;
log_fp = fopen(memmer_logfile,"at");
if (!log_fp) log_fp = stdout;
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());
}
fprintf(log_fp, "%s", buf);
return;
}
#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)
{
struct block *block = block_first;
struct unit_head_large *large = unit_head_large_first;
#ifdef LOG_MEMMGR
int count = 0;
#endif /* LOG_MEMMGR */
while (block) {
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[1024];
sprintf (buf,
"%04d : %s line %d size %lu address 0x%p\n", ++count,
head->file, head->line, (unsigned long)head->size, ptr);
memmgr_log (buf);
#endif /* LOG_MEMMGR */
// get block pointer and free it [celest]
_mfree(ptr, ALC_MARK);
}
}
}
block = block->block_next;
}
while(large) {
struct unit_head_large *large2;
#ifdef LOG_MEMMGR
char buf[1024];
sprintf (buf,
"%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 /* LOG_MEMMGR */
large2 = large->next;
FREE(large,file,line,func);
large = large2;
}
#ifdef LOG_MEMMGR
if(count == 0) {
ShowInfo("Memory manager: No memory leaks found.\n");
} else {
ShowWarning("Memory manager: Memory leaks found and fixed.\n");
fclose(log_fp);
}
#endif /* LOG_MEMMGR */
}
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);
memset(hash_unfill, 0, sizeof(hash_unfill));
#endif /* LOG_MEMMGR */
}
#endif /* USE_MEMMGR */
/*======================================
* Initialise
*--------------------------------------
*/
bool malloc_verify_ptr(void* ptr)
{
#ifdef USE_MEMMGR
return memmgr_verify(ptr);
#elif defined(DMALLOC)
return (dmalloc_verify(ptr) == DMALLOC_VERIFY_NOERROR);
#else
return true;
#endif
}
size_t malloc_usage (void)
{
#ifdef USE_MEMMGR
return memmgr_usage ();
#else
return 0;
#endif
}
void malloc_final (void)
{
#ifdef USE_MEMMGR
memmgr_final ();
#endif
#ifdef GCOLLECT
GC_find_leak = 1;
GC_gcollect();
#endif
}
void malloc_init (void)
{
#if defined(DMALLOC) && defined(CYGWIN)
// http://dmalloc.com/docs/latest/online/dmalloc_19.html
dmalloc_debug_setup(getenv("DMALLOC_OPTIONS"));
#endif
#ifdef GCOLLECT
GC_INIT();
#endif
#ifdef USE_MEMMGR
memmgr_init ();
#endif
}