malloc.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/malloc.h"
  4. #include "../common/core.h"
  5. #include "../common/showmsg.h"
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include <time.h>
  10. // no logging for minicore
  11. #if defined(MINICORE) && defined(LOG_MEMMGR)
  12. #undef LOG_MEMMGR
  13. #endif
  14. void* aMalloc_(size_t size, const char *file, int line, const char *func)
  15. {
  16. void *ret = MALLOC(size, file, line, func);
  17. // ShowMessage("%s:%d: in func %s: aMalloc %d\n",file,line,func,size);
  18. if (ret == NULL){
  19. ShowFatalError("%s:%d: in func %s: aMalloc error out of memory!\n",file,line,func);
  20. exit(EXIT_FAILURE);
  21. }
  22. return ret;
  23. }
  24. void* aMallocA_(size_t size, const char *file, int line, const char *func)
  25. {
  26. void *ret = MALLOCA(size, file, line, func);
  27. // ShowMessage("%s:%d: in func %s: aMallocA %d\n",file,line,func,size);
  28. if (ret == NULL){
  29. ShowFatalError("%s:%d: in func %s: aMallocA error out of memory!\n",file,line,func);
  30. exit(EXIT_FAILURE);
  31. }
  32. return ret;
  33. }
  34. void* aCalloc_(size_t num, size_t size, const char *file, int line, const char *func)
  35. {
  36. void *ret = CALLOC(num, size, file, line, func);
  37. // ShowMessage("%s:%d: in func %s: aCalloc %d %d\n",file,line,func,num,size);
  38. if (ret == NULL){
  39. ShowFatalError("%s:%d: in func %s: aCalloc error out of memory!\n", file, line, func);
  40. exit(EXIT_FAILURE);
  41. }
  42. return ret;
  43. }
  44. void* aCallocA_(size_t num, size_t size, const char *file, int line, const char *func)
  45. {
  46. void *ret = CALLOCA(num, size, file, line, func);
  47. // ShowMessage("%s:%d: in func %s: aCallocA %d %d\n",file,line,func,num,size);
  48. if (ret == NULL){
  49. ShowFatalError("%s:%d: in func %s: aCallocA error out of memory!\n",file,line,func);
  50. exit(EXIT_FAILURE);
  51. }
  52. return ret;
  53. }
  54. void* aRealloc_(void *p, size_t size, const char *file, int line, const char *func)
  55. {
  56. void *ret = REALLOC(p, size, file, line, func);
  57. // ShowMessage("%s:%d: in func %s: aRealloc %p %d\n",file,line,func,p,size);
  58. if (ret == NULL){
  59. ShowFatalError("%s:%d: in func %s: aRealloc error out of memory!\n",file,line,func);
  60. exit(EXIT_FAILURE);
  61. }
  62. return ret;
  63. }
  64. char* aStrdup_(const char *p, const char *file, int line, const char *func)
  65. {
  66. char *ret = STRDUP(p, file, line, func);
  67. // ShowMessage("%s:%d: in func %s: aStrdup %p\n",file,line,func,p);
  68. if (ret == NULL){
  69. ShowFatalError("%s:%d: in func %s: aStrdup error out of memory!\n", file, line, func);
  70. exit(EXIT_FAILURE);
  71. }
  72. return ret;
  73. }
  74. void aFree_(void *p, const char *file, int line, const char *func)
  75. {
  76. // ShowMessage("%s:%d: in func %s: aFree %p\n",file,line,func,p);
  77. if (p)
  78. FREE(p, file, line, func);
  79. p = NULL;
  80. }
  81. #ifdef GCOLLECT
  82. void* _bcallocA(size_t size, size_t cnt)
  83. {
  84. void *ret = MALLOCA(size * cnt);
  85. if (ret) memset(ret, 0, size * cnt);
  86. return ret;
  87. }
  88. void* _bcalloc(size_t size, size_t cnt)
  89. {
  90. void *ret = MALLOC(size * cnt);
  91. if (ret) memset(ret, 0, size * cnt);
  92. return ret;
  93. }
  94. char* _bstrdup(const char *chr)
  95. {
  96. int len = strlen(chr);
  97. char *ret = (char*)MALLOC(len + 1);
  98. if (ret) memcpy(ret, chr, len + 1);
  99. return ret;
  100. }
  101. #endif
  102. #ifdef USE_MEMMGR
  103. #define DEBUG_MEMMGR
  104. /* USE_MEMMGR */
  105. /*
  106. * メモリマネージャ
  107. * malloc , free の処理を効率的に出来るようにしたもの。
  108. * 複雑な処理を行っているので、若干重くなるかもしれません。
  109. *
  110. * データ構造など(説明下手ですいません^^; )
  111. * ・メモリを複数の「ブロック」に分けて、さらにブロックを複数の「ユニット」
  112. * に分けています。ユニットのサイズは、1ブロックの容量を複数個に均等配分
  113. * したものです。たとえば、1ユニット32KBの場合、ブロック1つは32Byteのユ
  114. * ニットが、1024個集まって出来ていたり、64Byteのユニットが 512個集まって
  115. * 出来ていたりします。(padding,unit_head を除く)
  116. *
  117. * ・ブロック同士はリンクリスト(block_prev,block_next) でつながり、同じサイ
  118. * ズを持つブロック同士もリンクリスト(hash_prev,hash_nect) でつな
  119. * がっています。それにより、不要となったメモリの再利用が効率的に行えます。
  120. */
  121. /* ブロックのアライメント */
  122. #define BLOCK_ALIGNMENT1 16
  123. #define BLOCK_ALIGNMENT2 64
  124. /* ブロックに入るデータ量 */
  125. #define BLOCK_DATA_COUNT1 128
  126. #define BLOCK_DATA_COUNT2 608
  127. /* ブロックの大きさ: 16*128 + 64*576 = 40KB */
  128. #define BLOCK_DATA_SIZE1 ( BLOCK_ALIGNMENT1 * BLOCK_DATA_COUNT1 )
  129. #define BLOCK_DATA_SIZE2 ( BLOCK_ALIGNMENT2 * BLOCK_DATA_COUNT2 )
  130. #define BLOCK_DATA_SIZE ( BLOCK_DATA_SIZE1 + BLOCK_DATA_SIZE2 )
  131. /* 一度に確保するブロックの数。 */
  132. #define BLOCK_ALLOC 104
  133. /* ブロック */
  134. struct block {
  135. struct block* block_next; /* 次に確保した領域 */
  136. struct block* unfill_prev; /* 次の埋まっていない領域 */
  137. struct block* unfill_next; /* 次の埋まっていない領域 */
  138. unsigned short unit_size; /* ユニットの大きさ */
  139. unsigned short unit_hash; /* ユニットのハッシュ */
  140. unsigned short unit_count; /* ユニットの個数 */
  141. unsigned short unit_used; /* 使用ユニット数 */
  142. unsigned short unit_unfill; /* 未使用ユニットの場所 */
  143. unsigned short unit_maxused; /* 使用ユニットの最大値 */
  144. char data[ BLOCK_DATA_SIZE ];
  145. };
  146. struct unit_head {
  147. struct block *block;
  148. const char* file;
  149. unsigned short line;
  150. unsigned short size;
  151. long checksum;
  152. };
  153. static struct block* hash_unfill[BLOCK_DATA_COUNT1 + BLOCK_DATA_COUNT2 + 1];
  154. static struct block* block_first, *block_last, block_head;
  155. /* メモリを使い回せない領域用のデータ */
  156. struct unit_head_large {
  157. size_t size;
  158. struct unit_head_large* prev;
  159. struct unit_head_large* next;
  160. struct unit_head unit_head;
  161. };
  162. static struct unit_head_large *unit_head_large_first = NULL;
  163. static struct block* block_malloc(unsigned short hash);
  164. static void block_free(struct block* p);
  165. static size_t memmgr_usage_bytes;
  166. #define block2unit(p, n) ((struct unit_head*)(&(p)->data[ p->unit_size * (n) ]))
  167. #define memmgr_assert(v) do { if(!(v)) { ShowError("Memory manager: assertion '" #v "' failed!\n"); } } while(0)
  168. static unsigned short size2hash( size_t size )
  169. {
  170. if( size <= BLOCK_DATA_SIZE1 ) {
  171. return (unsigned short)(size + BLOCK_ALIGNMENT1 - 1) / BLOCK_ALIGNMENT1;
  172. } else if( size <= BLOCK_DATA_SIZE ){
  173. return (unsigned short)(size - BLOCK_DATA_SIZE1 + BLOCK_ALIGNMENT2 - 1) / BLOCK_ALIGNMENT2
  174. + BLOCK_DATA_COUNT1;
  175. } else {
  176. return 0xffff; // ブロック長を超える場合は hash にしない
  177. }
  178. }
  179. static size_t hash2size( unsigned short hash )
  180. {
  181. if( hash <= BLOCK_DATA_COUNT1) {
  182. return hash * BLOCK_ALIGNMENT1;
  183. } else {
  184. return (hash - BLOCK_DATA_COUNT1) * BLOCK_ALIGNMENT2 + BLOCK_DATA_SIZE1;
  185. }
  186. }
  187. void* _mmalloc(size_t size, const char *file, int line, const char *func )
  188. {
  189. struct block *block;
  190. short size_hash = size2hash( size );
  191. struct unit_head *head;
  192. if (((long) size) < 0) {
  193. ShowError("_mmalloc: %d\n", size);
  194. return 0;
  195. }
  196. if(size == 0) {
  197. return NULL;
  198. }
  199. memmgr_usage_bytes += size;
  200. /* ブロック長を超える領域の確保には、malloc() を用いる */
  201. /* その際、unit_head.block に NULL を代入して区別する */
  202. if(hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
  203. struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func);
  204. if(p != NULL) {
  205. p->size = size;
  206. p->unit_head.block = NULL;
  207. p->unit_head.size = 0;
  208. p->unit_head.file = file;
  209. p->unit_head.line = line;
  210. p->prev = NULL;
  211. if (unit_head_large_first == NULL)
  212. p->next = NULL;
  213. else {
  214. unit_head_large_first->prev = p;
  215. p->next = unit_head_large_first;
  216. }
  217. unit_head_large_first = p;
  218. *(long*)((char*)p + sizeof(struct unit_head_large) - sizeof(long) + size) = 0xdeadbeaf;
  219. return (char *)p + sizeof(struct unit_head_large) - sizeof(long);
  220. } else {
  221. ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line);
  222. exit(EXIT_FAILURE);
  223. }
  224. }
  225. /* 同一サイズのブロックが確保されていない時、新たに確保する */
  226. if(hash_unfill[size_hash]) {
  227. block = hash_unfill[size_hash];
  228. } else {
  229. block = block_malloc(size_hash);
  230. }
  231. if( block->unit_unfill == 0xFFFF ) {
  232. // free済み領域が残っていない
  233. memmgr_assert(block->unit_used < block->unit_count);
  234. memmgr_assert(block->unit_used == block->unit_maxused);
  235. head = block2unit(block, block->unit_maxused);
  236. block->unit_used++;
  237. block->unit_maxused++;
  238. } else {
  239. head = block2unit(block, block->unit_unfill);
  240. block->unit_unfill = head->size;
  241. block->unit_used++;
  242. }
  243. if( block->unit_unfill == 0xFFFF && block->unit_maxused >= block->unit_count) {
  244. // ユニットを使い果たしたので、unfillリストから削除
  245. if( block->unfill_prev == &block_head) {
  246. hash_unfill[ size_hash ] = block->unfill_next;
  247. } else {
  248. block->unfill_prev->unfill_next = block->unfill_next;
  249. }
  250. if( block->unfill_next ) {
  251. block->unfill_next->unfill_prev = block->unfill_prev;
  252. }
  253. block->unfill_prev = NULL;
  254. }
  255. #ifdef DEBUG_MEMMGR
  256. {
  257. size_t i, sz = hash2size( size_hash );
  258. for( i=0; i<sz; i++ )
  259. {
  260. if( ((unsigned char*)head)[ sizeof(struct unit_head) - sizeof(long) + i] != 0xfd )
  261. {
  262. if( head->line != 0xfdfd )
  263. {
  264. ShowError("Memory manager: freed-data is changed. (freed in %s line %d)\n", head->file,head->line);
  265. }
  266. else
  267. {
  268. ShowError("Memory manager: not-allocated-data is changed.\n");
  269. }
  270. break;
  271. }
  272. }
  273. memset( (char *)head + sizeof(struct unit_head) - sizeof(long), 0xcd, sz );
  274. }
  275. #endif
  276. head->block = block;
  277. head->file = file;
  278. head->line = line;
  279. head->size = (unsigned short)size;
  280. *(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + size) = 0xdeadbeaf;
  281. return (char *)head + sizeof(struct unit_head) - sizeof(long);
  282. };
  283. void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func )
  284. {
  285. void *p = _mmalloc(num * size,file,line,func);
  286. memset(p,0,num * size);
  287. return p;
  288. }
  289. void* _mrealloc(void *memblock, size_t size, const char *file, int line, const char *func )
  290. {
  291. size_t old_size;
  292. if(memblock == NULL) {
  293. return _mmalloc(size,file,line,func);
  294. }
  295. old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(long)))->size;
  296. if( old_size == 0 ) {
  297. old_size = ((struct unit_head_large *)((char *)memblock - sizeof(struct unit_head_large) + sizeof(long)))->size;
  298. }
  299. if(old_size > size) {
  300. // サイズ縮小 -> そのまま返す(手抜き)
  301. return memblock;
  302. } else {
  303. // サイズ拡大
  304. void *p = _mmalloc(size,file,line,func);
  305. if(p != NULL) {
  306. memcpy(p,memblock,old_size);
  307. }
  308. _mfree(memblock,file,line,func);
  309. return p;
  310. }
  311. }
  312. char* _mstrdup(const char *p, const char *file, int line, const char *func )
  313. {
  314. if(p == NULL) {
  315. return NULL;
  316. } else {
  317. size_t len = strlen(p);
  318. char *string = (char *)_mmalloc(len + 1,file,line,func);
  319. memcpy(string,p,len+1);
  320. return string;
  321. }
  322. }
  323. void _mfree(void *ptr, const char *file, int line, const char *func )
  324. {
  325. struct unit_head *head;
  326. if (ptr == NULL)
  327. return;
  328. head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(long));
  329. if(head->size == 0) {
  330. /* malloc() で直に確保された領域 */
  331. struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(long));
  332. if(
  333. *(long*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(long) + head_large->size)
  334. != 0xdeadbeaf)
  335. {
  336. ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line);
  337. } else {
  338. head->size = -1;
  339. if(head_large->prev) {
  340. head_large->prev->next = head_large->next;
  341. } else {
  342. unit_head_large_first = head_large->next;
  343. }
  344. if(head_large->next) {
  345. head_large->next->prev = head_large->prev;
  346. }
  347. memmgr_usage_bytes -= head_large->size;
  348. #ifdef DEBUG_MEMMGR
  349. // set freed memory to 0xfd
  350. memset(ptr, 0xfd, head_large->size);
  351. #endif
  352. FREE(head_large,file,line,func);
  353. }
  354. } else {
  355. /* ユニット解放 */
  356. struct block *block = head->block;
  357. if( (char*)head - (char*)block > sizeof(struct block) ) {
  358. ShowError("Memory manager: args of aFree 0x%p is invalid pointer %s line %d\n", ptr, file, line);
  359. } else if(head->block == NULL) {
  360. ShowError("Memory manager: args of aFree 0x%p is freed pointer %s:%d@%s\n", ptr, file, line, func);
  361. } else if(*(long*)((char*)head + sizeof(struct unit_head) - sizeof(long) + head->size) != 0xdeadbeaf) {
  362. ShowError("Memory manager: args of aFree 0x%p is overflowed pointer %s line %d\n", ptr, file, line);
  363. } else {
  364. memmgr_usage_bytes -= head->size;
  365. head->block = NULL;
  366. #ifdef DEBUG_MEMMGR
  367. memset(ptr, 0xfd, block->unit_size - sizeof(struct unit_head) + sizeof(long) );
  368. head->file = file;
  369. head->line = line;
  370. #endif
  371. memmgr_assert( block->unit_used > 0 );
  372. if(--block->unit_used == 0) {
  373. /* ブロックの解放 */
  374. block_free(block);
  375. } else {
  376. if( block->unfill_prev == NULL) {
  377. // unfill リストに追加
  378. if( hash_unfill[ block->unit_hash ] ) {
  379. hash_unfill[ block->unit_hash ]->unfill_prev = block;
  380. }
  381. block->unfill_prev = &block_head;
  382. block->unfill_next = hash_unfill[ block->unit_hash ];
  383. hash_unfill[ block->unit_hash ] = block;
  384. }
  385. head->size = block->unit_unfill;
  386. block->unit_unfill = (unsigned short)(((unsigned long)head - (unsigned long)block->data) / block->unit_size);
  387. }
  388. }
  389. }
  390. }
  391. /* ブロックを確保する */
  392. static struct block* block_malloc(unsigned short hash)
  393. {
  394. int i;
  395. struct block *p;
  396. if(hash_unfill[0] != NULL) {
  397. /* ブロック用の領域は確保済み */
  398. p = hash_unfill[0];
  399. hash_unfill[0] = hash_unfill[0]->unfill_next;
  400. } else {
  401. /* ブロック用の領域を新たに確保する */
  402. p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__ );
  403. if(p == NULL) {
  404. ShowFatalError("Memory manager::block_alloc failed.\n");
  405. exit(EXIT_FAILURE);
  406. }
  407. if(block_first == NULL) {
  408. /* 初回確保 */
  409. block_first = p;
  410. } else {
  411. block_last->block_next = p;
  412. }
  413. block_last = &p[BLOCK_ALLOC - 1];
  414. block_last->block_next = NULL;
  415. /* ブロックを連結させる */
  416. for(i=0;i<BLOCK_ALLOC;i++) {
  417. if(i != 0) {
  418. // p[0] はこれから使うのでリンクには加えない
  419. p[i].unfill_next = hash_unfill[0];
  420. hash_unfill[0] = &p[i];
  421. p[i].unfill_prev = NULL;
  422. p[i].unit_used = 0;
  423. }
  424. if(i != BLOCK_ALLOC -1) {
  425. p[i].block_next = &p[i+1];
  426. }
  427. }
  428. }
  429. // unfill に追加
  430. memmgr_assert(hash_unfill[ hash ] == NULL);
  431. hash_unfill[ hash ] = p;
  432. p->unfill_prev = &block_head;
  433. p->unfill_next = NULL;
  434. p->unit_size = (unsigned short)(hash2size( hash ) + sizeof(struct unit_head));
  435. p->unit_hash = hash;
  436. p->unit_count = BLOCK_DATA_SIZE / p->unit_size;
  437. p->unit_used = 0;
  438. p->unit_unfill = 0xFFFF;
  439. p->unit_maxused = 0;
  440. #ifdef DEBUG_MEMMGR
  441. memset( p->data, 0xfd, sizeof(p->data) );
  442. #endif
  443. return p;
  444. }
  445. static void block_free(struct block* p)
  446. {
  447. if( p->unfill_prev ) {
  448. if( p->unfill_prev == &block_head) {
  449. hash_unfill[ p->unit_hash ] = p->unfill_next;
  450. } else {
  451. p->unfill_prev->unfill_next = p->unfill_next;
  452. }
  453. if( p->unfill_next ) {
  454. p->unfill_next->unfill_prev = p->unfill_prev;
  455. }
  456. p->unfill_prev = NULL;
  457. }
  458. p->unfill_next = hash_unfill[0];
  459. hash_unfill[0] = p;
  460. }
  461. unsigned int memmgr_usage (void)
  462. {
  463. return memmgr_usage_bytes / 1024;
  464. }
  465. #ifdef LOG_MEMMGR
  466. static char memmer_logfile[128];
  467. static FILE *log_fp;
  468. static void memmgr_log (char *buf)
  469. {
  470. if( !log_fp )
  471. {
  472. time_t raw;
  473. struct tm* t;
  474. log_fp = fopen(memmer_logfile,"at");
  475. if (!log_fp) log_fp = stdout;
  476. time(&raw);
  477. t = localtime(&raw);
  478. fprintf(log_fp, "\nMemory manager: Memory leaks found at %d/%02d/%02d %02dh%02dm%02ds (Revision %s).\n",
  479. (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, get_svn_revision());
  480. }
  481. fprintf(log_fp, "%s", buf);
  482. return;
  483. }
  484. #endif /* LOG_MEMMGR */
  485. /// Returns true if the memory location is active.
  486. /// Active means it is allocated and points to a usable part.
  487. ///
  488. /// @param ptr Pointer to the memory
  489. /// @return true if the memory is active
  490. bool memmgr_verify(void* ptr)
  491. {
  492. struct block* block = block_first;
  493. struct unit_head_large* large = unit_head_large_first;
  494. if( ptr == NULL )
  495. return false;// never valid
  496. // search small blocks
  497. while( block )
  498. {
  499. if( (char*)ptr >= (char*)block && (char*)ptr < ((char*)block) + sizeof(struct block) )
  500. {// found memory block
  501. if( block->unit_used && (char*)ptr >= block->data )
  502. {// memory block is being used and ptr points to a sub-unit
  503. size_t i = (size_t)((char*)ptr - block->data)/block->unit_size;
  504. struct unit_head* head = block2unit(block, i);
  505. if( i < block->unit_maxused && head->block != NULL )
  506. {// memory unit is allocated, check if ptr points to the usable part
  507. return ( (char*)ptr >= ((char*)head) + sizeof(struct unit_head) - sizeof(long)
  508. && (char*)ptr < ((char*)head) + sizeof(struct unit_head) - sizeof(long) + head->size );
  509. }
  510. }
  511. return false;
  512. }
  513. block = block->block_next;
  514. }
  515. // search large blocks
  516. while( large )
  517. {
  518. if( (char*)ptr >= (char*)large && (char*)ptr < ((char*)large) + large->size )
  519. {// found memory block, check if ptr points to the usable part
  520. return ( (char*)ptr >= ((char*)large) + sizeof(struct unit_head_large) - sizeof(long)
  521. && (char*)ptr < ((char*)large) + sizeof(struct unit_head_large) - sizeof(long) + large->size );
  522. }
  523. large = large->next;
  524. }
  525. return false;
  526. }
  527. static void memmgr_final (void)
  528. {
  529. struct block *block = block_first;
  530. struct unit_head_large *large = unit_head_large_first;
  531. #ifdef LOG_MEMMGR
  532. int count = 0;
  533. #endif /* LOG_MEMMGR */
  534. while (block) {
  535. if (block->unit_used) {
  536. int i;
  537. for (i = 0; i < block->unit_maxused; i++) {
  538. struct unit_head *head = block2unit(block, i);
  539. if(head->block != NULL) {
  540. char* ptr = (char *)head + sizeof(struct unit_head) - sizeof(long);
  541. #ifdef LOG_MEMMGR
  542. char buf[1024];
  543. sprintf (buf,
  544. "%04d : %s line %d size %lu address 0x%p\n", ++count,
  545. head->file, head->line, (unsigned long)head->size, ptr);
  546. memmgr_log (buf);
  547. #endif /* LOG_MEMMGR */
  548. // get block pointer and free it [celest]
  549. _mfree(ptr, ALC_MARK);
  550. }
  551. }
  552. }
  553. block = block->block_next;
  554. }
  555. while(large) {
  556. struct unit_head_large *large2;
  557. #ifdef LOG_MEMMGR
  558. char buf[1024];
  559. sprintf (buf,
  560. "%04d : %s line %d size %lu address 0x%p\n", ++count,
  561. large->unit_head.file, large->unit_head.line, (unsigned long)large->size, &large->unit_head.checksum);
  562. memmgr_log (buf);
  563. #endif /* LOG_MEMMGR */
  564. large2 = large->next;
  565. FREE(large,file,line,func);
  566. large = large2;
  567. }
  568. #ifdef LOG_MEMMGR
  569. if(count == 0) {
  570. ShowInfo("Memory manager: No memory leaks found.\n");
  571. } else {
  572. ShowWarning("Memory manager: Memory leaks found and fixed.\n");
  573. fclose(log_fp);
  574. }
  575. #endif /* LOG_MEMMGR */
  576. return;
  577. }
  578. static void memmgr_init (void)
  579. {
  580. #ifdef LOG_MEMMGR
  581. sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME);
  582. ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile);
  583. memset(hash_unfill, 0, sizeof(hash_unfill));
  584. #endif /* LOG_MEMMGR */
  585. return;
  586. }
  587. #endif /* USE_MEMMGR */
  588. /*======================================
  589. * Initialise
  590. *--------------------------------------
  591. */
  592. bool malloc_verify(void* ptr)
  593. {
  594. #ifdef USE_MEMMGR
  595. return memmgr_verify(ptr);
  596. #else
  597. return true;
  598. #endif
  599. }
  600. unsigned int malloc_usage (void)
  601. {
  602. #ifdef USE_MEMMGR
  603. return memmgr_usage ();
  604. #else
  605. return 0;
  606. #endif
  607. }
  608. void malloc_final (void)
  609. {
  610. #ifdef USE_MEMMGR
  611. memmgr_final ();
  612. #endif
  613. return;
  614. }
  615. void malloc_init (void)
  616. {
  617. #ifdef USE_MEMMGR
  618. memmgr_init ();
  619. #endif
  620. return;
  621. }