
* Moved memory library selection to malloc.c to avoid poisoning the namespace of the rest of the code. * Removed BCHECK code since it's unneeded. (bcheck is an external batch tool that runs on top of the dbx debugger) * Fixed GCOLLECT usage. (missing init and final memory leak check) * Fixed DMALLOC usage. (missing options on CYGWIN and verify memory) * Renamed malloc_verify to malloc_verify_ptr to avoid conflict with DMALLOC. * Changed itemtype from inline to static inline to avoid error with the SunOS compiler. git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@14913 54d463be-8e91-2dee-dedb-b68131a5f0ec
750 lines
21 KiB
C
750 lines
21 KiB
C
// 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 MALLOCA(n,file,line,func) mwMalloc((n),(file),(line))
|
||
# define CALLOC(m,n,file,line,func) mwCalloc((m),(n),(file),(line))
|
||
# define CALLOCA(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 MALLOCA(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 CALLOCA(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 MALLOCA(n,file,line,func) GC_MALLOC_ATOMIC(n)
|
||
# define CALLOC(m,n,file,line,func) _bcalloc((m),(n))
|
||
# define CALLOCA(m,n,file,line,func) _bcallocA((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)
|
||
|
||
void * _bcalloc(size_t, size_t);
|
||
void * _bcallocA(size_t, size_t);
|
||
char * _bstrdup(const char *);
|
||
|
||
#else
|
||
|
||
# define MALLOC(n,file,line,func) malloc(n)
|
||
# define MALLOCA(n,file,line,func) malloc(n)
|
||
# define CALLOC(m,n,file,line,func) calloc((m),(n))
|
||
# define CALLOCA(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* aMallocA_(size_t size, const char *file, int line, const char *func)
|
||
{
|
||
void *ret = MALLOCA(size, file, line, func);
|
||
// ShowMessage("%s:%d: in func %s: aMallocA %d\n",file,line,func,size);
|
||
if (ret == NULL){
|
||
ShowFatalError("%s:%d: in func %s: aMallocA 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* aCallocA_(size_t num, size_t size, const char *file, int line, const char *func)
|
||
{
|
||
void *ret = CALLOCA(num, size, file, line, func);
|
||
// ShowMessage("%s:%d: in func %s: aCallocA %d %d\n",file,line,func,num,size);
|
||
if (ret == NULL){
|
||
ShowFatalError("%s:%d: in func %s: aCallocA 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
|
||
|
||
void* _bcallocA(size_t size, size_t cnt)
|
||
{
|
||
void *ret = GC_MALLOC_ATOMIC(size * cnt);
|
||
if (ret) memset(ret, 0, size * cnt);
|
||
return ret;
|
||
}
|
||
void* _bcalloc(size_t size, size_t cnt)
|
||
{
|
||
void *ret = GC_MALLOC(size * cnt);
|
||
if (ret) memset(ret, 0, size * cnt);
|
||
return ret;
|
||
}
|
||
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
|
||
}
|