malloc.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "malloc.h"
  7. #include "../common/core.h"
  8. #include "../common/showmsg.h"
  9. #ifdef MINICORE
  10. #undef LOG_MEMMGR
  11. #endif
  12. void* aMalloc_ (size_t size, const char *file, int line, const char *func)
  13. {
  14. #ifndef MEMWATCH
  15. void *ret = MALLOC(size);
  16. #else
  17. void *ret = mwMalloc(size, file, line);
  18. #endif
  19. // ShowMessage("%s:%d: in func %s: malloc %d\n",file,line,func,size);
  20. if (ret == NULL){
  21. ShowFatalError("%s:%d: in func %s: malloc error out of memory!\n",file,line,func);
  22. exit(1);
  23. }
  24. return ret;
  25. }
  26. void* aMallocA_ (size_t size, const char *file, int line, const char *func)
  27. {
  28. #ifndef MEMWATCH
  29. void *ret = MALLOCA(size);
  30. #else
  31. void *ret = mwMalloc(size, file, line);
  32. #endif
  33. // ShowMessage("%s:%d: in func %s: malloc %d\n",file,line,func,size);
  34. if (ret == NULL){
  35. ShowFatalError("%s:%d: in func %s: malloc error out of memory!\n",file,line,func);
  36. exit(1);
  37. }
  38. return ret;
  39. }
  40. void* aCalloc_ (size_t num, size_t size, const char *file, int line, const char *func)
  41. {
  42. #ifndef MEMWATCH
  43. void *ret = CALLOC(num, size);
  44. #else
  45. void *ret = mwCalloc(num, size, file, line);
  46. #endif
  47. // ShowMessage("%s:%d: in func %s: calloc %d %d\n",file,line,func,num,size);
  48. if (ret == NULL){
  49. ShowFatalError("%s:%d: in func %s: calloc error out of memory!\n", file, line, func);
  50. exit(1);
  51. }
  52. return ret;
  53. }
  54. void* aCallocA_ (size_t num, size_t size, const char *file, int line, const char *func)
  55. {
  56. #ifndef MEMWATCH
  57. void *ret = CALLOCA(num, size);
  58. #else
  59. void *ret = mwCalloc(num, size, file, line);
  60. #endif
  61. // ShowMessage("%s:%d: in func %s: calloc %d %d\n",file,line,func,num,size);
  62. if (ret == NULL){
  63. ShowFatalError("%s:%d: in func %s: calloc error out of memory!\n",file,line,func);
  64. exit(1);
  65. }
  66. return ret;
  67. }
  68. void* aRealloc_ (void *p, size_t size, const char *file, int line, const char *func)
  69. {
  70. #ifndef MEMWATCH
  71. void *ret = REALLOC(p, size);
  72. #else
  73. void *ret = mwRealloc(p, size, file, line);
  74. #endif
  75. // ShowMessage("%s:%d: in func %s: realloc %p %d\n",file,line,func,p,size);
  76. if (ret == NULL){
  77. ShowFatalError("%s:%d: in func %s: realloc error out of memory!\n",file,line,func);
  78. exit(1);
  79. }
  80. return ret;
  81. }
  82. char* aStrdup_ (const char *p, const char *file, int line, const char *func)
  83. {
  84. #ifndef MEMWATCH
  85. char *ret = STRDUP(p);
  86. #else
  87. char *ret = mwStrdup(p, file, line);
  88. #endif
  89. // ShowMessage("%s:%d: in func %s: strdup %p\n",file,line,func,p);
  90. if (ret == NULL){
  91. ShowFatalError("%s:%d: in func %s: strdup error out of memory!\n", file, line, func);
  92. exit(1);
  93. }
  94. return ret;
  95. }
  96. void aFree_ (void *p, const char *file, int line, const char *func)
  97. {
  98. // ShowMessage("%s:%d: in func %s: free %p\n",file,line,func,p);
  99. if (p)
  100. #ifndef MEMWATCH
  101. FREE(p);
  102. #else
  103. mwFree(p, file, line);
  104. #endif
  105. p = NULL;
  106. }
  107. #ifdef GCOLLECT
  108. void* _bcallocA(size_t size, size_t cnt)
  109. {
  110. void *ret = MALLOCA(size * cnt);
  111. if (ret) memset(ret, 0, size * cnt);
  112. return ret;
  113. }
  114. void* _bcalloc(size_t size, size_t cnt)
  115. {
  116. void *ret = MALLOC(size * cnt);
  117. if (ret) memset(ret, 0, size * cnt);
  118. return ret;
  119. }
  120. char* _bstrdup(const char *chr)
  121. {
  122. int len = strlen(chr);
  123. char *ret = (char*)MALLOC(len + 1);
  124. if (ret) memcpy(ret, chr, len + 1);
  125. return ret;
  126. }
  127. #endif
  128. #ifdef USE_MEMMGR
  129. /* USE_MEMMGR */
  130. /*
  131. * メモリマネージャ
  132. * malloc , free の処理を効率的に出来るようにしたもの。
  133. * 複雑な処理を行っているので、若干重くなるかもしれません。
  134. *
  135. * データ構造など(説明下手ですいません^^; )
  136. * ・メモリを複数の「ブロック」に分けて、さらにブロックを複数の「ユニット」
  137. * に分けています。ユニットのサイズは、1ブロックの容量を複数個に均等配分
  138. * したものです。たとえば、1ユニット32KBの場合、ブロック1つは32Byteのユ
  139. * ニットが、1024個集まって出来ていたり、64Byteのユニットが 512個集まって
  140. * 出来ていたりします。(padding,unit_head を除く)
  141. *
  142. * ・ブロック同士はリンクリスト(block_prev,block_next) でつながり、同じサイ
  143. * ズを持つブロック同士もリンクリスト(samesize_prev,samesize_nect) でつな
  144. * がっています。それにより、不要となったメモリの再利用が効率的に行えます。
  145. */
  146. /* ブロックに入るデータ量 */
  147. #define BLOCK_DATA_SIZE 80*1024
  148. /* 一度に確保するブロックの数。 */
  149. #define BLOCK_ALLOC 32
  150. /* ブロックのアライメント */
  151. #define BLOCK_ALIGNMENT 64
  152. /* ブロック */
  153. struct block {
  154. int block_no; /* ブロック番号 */
  155. struct block* block_prev; /* 前に確保した領域 */
  156. struct block* block_next; /* 次に確保した領域 */
  157. int samesize_no; /* 同じサイズの番号 */
  158. struct block* samesize_prev; /* 同じサイズの前の領域 */
  159. struct block* samesize_next; /* 同じサイズの次の領域 */
  160. size_t unit_size; /* ユニットのバイト数 0=未使用 */
  161. size_t unit_hash; /* ユニットのハッシュ */
  162. int unit_count; /* ユニットの数 */
  163. int unit_used; /* 使用済みユニット */
  164. char data[BLOCK_DATA_SIZE];
  165. };
  166. struct unit_head {
  167. struct block* block;
  168. size_t size;
  169. const char* file;
  170. int line;
  171. unsigned int checksum;
  172. };
  173. struct chunk {
  174. char *block;
  175. struct chunk *next;
  176. };
  177. static struct block* block_first = NULL;
  178. static struct block* block_last = NULL;
  179. static struct block* block_unused = NULL;
  180. /* ユニットへのハッシュ。80KB/64Byte = 1280個 */
  181. static struct block* unit_first[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 最初 */
  182. static struct block* unit_unfill[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 埋まってない */
  183. static struct block* unit_last[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 最後 */
  184. /* メモリを使い回せない領域用のデータ */
  185. struct unit_head_large {
  186. struct unit_head_large* prev;
  187. struct unit_head_large* next;
  188. struct unit_head unit_head;
  189. };
  190. static struct unit_head_large *unit_head_large_first = NULL;
  191. static struct chunk *chunk_first = NULL;
  192. static struct block* block_malloc(void);
  193. static void block_free(struct block* p);
  194. static void memmgr_info(void);
  195. static unsigned int memmgr_usage_bytes = 0;
  196. void* _mmalloc(size_t size, const char *file, int line, const char *func ) {
  197. int i;
  198. struct block *block;
  199. size_t size_hash;
  200. if (((long) size) < 0) {
  201. printf("_mmalloc: %d\n", size);
  202. return 0;
  203. }
  204. size_hash = (size+BLOCK_ALIGNMENT-1) / BLOCK_ALIGNMENT;
  205. if(size == 0) {
  206. return NULL;
  207. }
  208. memmgr_usage_bytes += size;
  209. /* ブロック長を超える領域の確保には、malloc() を用いる */
  210. /* その際、unit_head.block に NULL を代入して区別する */
  211. if(size_hash * BLOCK_ALIGNMENT > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
  212. #ifdef MEMWATCH
  213. struct unit_head_large* p = (struct unit_head_large*)mwMalloc(sizeof(struct unit_head_large) + size,file,line);
  214. #else
  215. struct unit_head_large* p = (struct unit_head_large*) MALLOC (sizeof(struct unit_head_large) + size);
  216. #endif
  217. if(p != NULL) {
  218. p->unit_head.block = NULL;
  219. p->unit_head.size = size;
  220. p->unit_head.file = file;
  221. p->unit_head.line = line;
  222. p->prev = NULL;
  223. if (unit_head_large_first == NULL)
  224. p->next = NULL;
  225. else {
  226. unit_head_large_first->prev = p;
  227. p->next = unit_head_large_first;
  228. }
  229. unit_head_large_first = p;
  230. *(int*)((char*)p + sizeof(struct unit_head_large) - sizeof(int) + size) = 0xdeadbeaf;
  231. return (char *)p + sizeof(struct unit_head_large) - sizeof(int);
  232. } else {
  233. ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line);
  234. exit(1);
  235. }
  236. }
  237. /* 同一サイズのブロックが確保されていない時、新たに確保する */
  238. if(unit_unfill[size_hash] == NULL) {
  239. block = block_malloc();
  240. if(unit_first[size_hash] == NULL) {
  241. /* 初回確保 */
  242. unit_first[size_hash] = block;
  243. unit_last[size_hash] = block;
  244. block->samesize_no = 0;
  245. block->samesize_prev = NULL;
  246. block->samesize_next = NULL;
  247. } else {
  248. /* 連結作業 */
  249. unit_last[size_hash]->samesize_next = block;
  250. block->samesize_no = unit_last[size_hash]->samesize_no + 1;
  251. block->samesize_prev = unit_last[size_hash];
  252. block->samesize_next = NULL;
  253. unit_last[size_hash] = block;
  254. }
  255. unit_unfill[size_hash] = block;
  256. block->unit_size = size_hash * BLOCK_ALIGNMENT + sizeof(struct unit_head);
  257. block->unit_count = (int)(BLOCK_DATA_SIZE / block->unit_size);
  258. block->unit_used = 0;
  259. block->unit_hash = size_hash;
  260. /* 未使用Flagを立てる */
  261. for(i=0;i<block->unit_count;i++) {
  262. ((struct unit_head*)(&block->data[block->unit_size * i]))->block = NULL;
  263. }
  264. }
  265. /* ユニット使用個数加算 */
  266. block = unit_unfill[size_hash];
  267. block->unit_used++;
  268. /* ユニット内を全て使い果たした */
  269. if(block->unit_count == block->unit_used) {
  270. do {
  271. unit_unfill[size_hash] = unit_unfill[size_hash]->samesize_next;
  272. } while(
  273. unit_unfill[size_hash] != NULL &&
  274. unit_unfill[size_hash]->unit_count == unit_unfill[size_hash]->unit_used
  275. );
  276. }
  277. /* ブロックの中の空きユニット捜索 */
  278. for(i=0;i<block->unit_count;i++) {
  279. struct unit_head *head = (struct unit_head*)(&block->data[block->unit_size * i]);
  280. if(head->block == NULL) {
  281. head->block = block;
  282. head->size = size;
  283. head->line = line;
  284. head->file = file;
  285. *(int*)((char*)head + sizeof(struct unit_head) - sizeof(int) + size) = 0xdeadbeaf;
  286. return (char *)head + sizeof(struct unit_head) - sizeof(int);
  287. }
  288. }
  289. // ここに来てはいけない。
  290. ShowFatalError("Memory manager::memmgr_malloc() serious error (allocating %d+%d bytes at %s:%d)\n", sizeof(struct unit_head_large), size, file, line);
  291. memmgr_info();
  292. exit(1);
  293. return NULL;
  294. };
  295. void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func ) {
  296. void *p = _mmalloc(num * size,file,line,func);
  297. memset(p,0,num * size);
  298. return p;
  299. }
  300. void* _mrealloc(void *memblock, size_t size, const char *file, int line, const char *func ) {
  301. size_t old_size;
  302. if(memblock == NULL) {
  303. return _mmalloc(size,file,line,func);
  304. }
  305. old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(int)))->size;
  306. if(old_size > size) {
  307. // サイズ縮小 -> そのまま返す(手抜き)
  308. return memblock;
  309. } else {
  310. // サイズ拡大
  311. void *p = _mmalloc(size,file,line,func);
  312. if(p != NULL) {
  313. memcpy(p,memblock,old_size);
  314. }
  315. _mfree(memblock,file,line,func);
  316. return p;
  317. }
  318. }
  319. char* _mstrdup(const char *p, const char *file, int line, const char *func ) {
  320. if(p == NULL) {
  321. return NULL;
  322. } else {
  323. size_t len = strlen(p);
  324. char *string = (char *)_mmalloc(len + 1,file,line,func);
  325. memcpy(string,p,len+1);
  326. return string;
  327. }
  328. }
  329. void _mfree(void *ptr, const char *file, int line, const char *func ) {
  330. struct unit_head *head;
  331. size_t size_hash;
  332. if (ptr == NULL)
  333. return;
  334. head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(int));
  335. size_hash = (head->size+BLOCK_ALIGNMENT-1) / BLOCK_ALIGNMENT;
  336. if(head->block == NULL) {
  337. if(size_hash * BLOCK_ALIGNMENT > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
  338. /* malloc() で直に確保された領域 */
  339. struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(int));
  340. if(
  341. *(int*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(int) + head->size)
  342. != 0xdeadbeaf)
  343. {
  344. ShowError("Memory manager: args of aFree is overflowed pointer %s line %d\n", file, line);
  345. }
  346. if(head_large->prev) {
  347. head_large->prev->next = head_large->next;
  348. } else {
  349. unit_head_large_first = head_large->next;
  350. }
  351. if(head_large->next) {
  352. head_large->next->prev = head_large->prev;
  353. }
  354. head->block = NULL;
  355. memmgr_usage_bytes -= head->size;
  356. FREE (head_large);
  357. } else {
  358. ShowError("Memory manager: args of aFree is freed pointer %s:%d@%s\n", file, line, func);
  359. }
  360. ptr = NULL;
  361. return;
  362. } else {
  363. /* ユニット解放 */
  364. struct block *block = head->block;
  365. if((unsigned long)block % sizeof(struct block) != 0) {
  366. ShowError("Memory manager: args of aFree is not valid pointer %s line %d\n", file, line);
  367. } else if(*(int*)((char*)head + sizeof(struct unit_head) - sizeof(int) + head->size) != 0xdeadbeaf) {
  368. ShowError("Memory manager: args of aFree is overflowed pointer %s line %d\n", file, line);
  369. } else {
  370. head->block = NULL;
  371. memmgr_usage_bytes -= head->size;
  372. if(--block->unit_used == 0) {
  373. /* ブロックの解放 */
  374. if(unit_unfill[block->unit_hash] == block) {
  375. /* 空きユニットに指定されている */
  376. do {
  377. unit_unfill[block->unit_hash] = unit_unfill[block->unit_hash]->samesize_next;
  378. } while(
  379. unit_unfill[block->unit_hash] != NULL &&
  380. unit_unfill[block->unit_hash]->unit_count == unit_unfill[block->unit_hash]->unit_used
  381. );
  382. }
  383. if(block->samesize_prev == NULL && block->samesize_next == NULL) {
  384. /* 独立ブロックの解放 */
  385. unit_first[block->unit_hash] = NULL;
  386. unit_last[block->unit_hash] = NULL;
  387. unit_unfill[block->unit_hash] = NULL;
  388. } else if(block->samesize_prev == NULL) {
  389. /* 先頭ブロックの解放 */
  390. unit_first[block->unit_hash] = block->samesize_next;
  391. (block->samesize_next)->samesize_prev = NULL;
  392. } else if(block->samesize_next == NULL) {
  393. /* 末端ブロックの解放 */
  394. unit_last[block->unit_hash] = block->samesize_prev;
  395. (block->samesize_prev)->samesize_next = NULL;
  396. } else {
  397. /* 中間ブロックの解放 */
  398. (block->samesize_next)->samesize_prev = block->samesize_prev;
  399. (block->samesize_prev)->samesize_next = block->samesize_next;
  400. }
  401. block_free(block);
  402. } else {
  403. /* 空きユニットの再設定 */
  404. if(
  405. unit_unfill[block->unit_hash] == NULL ||
  406. unit_unfill[block->unit_hash]->samesize_no > block->samesize_no
  407. ) {
  408. unit_unfill[block->unit_hash] = block;
  409. }
  410. }
  411. ptr = NULL;
  412. }
  413. }
  414. }
  415. /* 現在の状況を表示する */
  416. static void memmgr_info(void) {
  417. int i;
  418. struct block *p;
  419. ShowInfo("** Memory Manager Information **\n");
  420. if(block_first == NULL) {
  421. ShowMessage("Uninitialized.\n");
  422. return;
  423. }
  424. ShowMessage(
  425. "Blocks: %04u , BlockSize: %06u Byte , Used: %08uKB\n",
  426. block_last->block_no+1,sizeof(struct block),
  427. (block_last->block_no+1) * sizeof(struct block) / 1024
  428. );
  429. p = block_first;
  430. for(i=0;i<=block_last->block_no;i++) {
  431. ShowMessage(" Block #%04u : ",p->block_no);
  432. if(p->unit_size == 0) {
  433. ShowMessage("unused.\n");
  434. } else {
  435. ShowMessage(
  436. "size: %05u byte. used: %04u/%04u prev:",
  437. p->unit_size - sizeof(struct unit_head),p->unit_used,p->unit_count
  438. );
  439. if(p->samesize_prev == NULL) {
  440. ShowMessage("NULL");
  441. } else {
  442. ShowMessage("%04u",(p->samesize_prev)->block_no);
  443. }
  444. ShowMessage(" next:");
  445. if(p->samesize_next == NULL) {
  446. ShowMessage("NULL");
  447. } else {
  448. ShowMessage("%04u",(p->samesize_next)->block_no);
  449. }
  450. ShowMessage("\n");
  451. }
  452. p = p->block_next;
  453. }
  454. }
  455. /* ブロックを確保する */
  456. static struct block* block_malloc(void) {
  457. if(block_unused != NULL) {
  458. /* ブロック用の領域は確保済み */
  459. struct block* ret = block_unused;
  460. do {
  461. block_unused = block_unused->block_next;
  462. } while(block_unused != NULL && block_unused->unit_size != 0);
  463. return ret;
  464. } else {
  465. /* ブロック用の領域を新たに確保する */
  466. int i;
  467. int block_no;
  468. struct block* p;
  469. struct chunk* chunk;
  470. char *pb = (char *) CALLOC (sizeof(struct block),BLOCK_ALLOC + 1);
  471. if(pb == NULL) {
  472. ShowFatalError("Memory manager::block_alloc failed.\n");
  473. exit(1);
  474. }
  475. // store original block address in chunk
  476. chunk = (struct chunk *) MALLOC (sizeof(struct chunk));
  477. if (chunk == NULL) {
  478. ShowFatalError("Memory manager::block_alloc failed.\n");
  479. exit(1);
  480. }
  481. chunk->block = pb;
  482. chunk->next = (chunk_first) ? chunk_first : NULL;
  483. chunk_first = chunk;
  484. // ブロックのポインタの先頭をsizeof(block) アライメントに揃える
  485. // このアドレスをfree() することはないので、直接ポインタを変更している。
  486. pb += sizeof(struct block) - ((unsigned long)pb % sizeof(struct block));
  487. p = (struct block*)pb;
  488. if(block_first == NULL) {
  489. /* 初回確保 */
  490. block_no = 0;
  491. block_first = p;
  492. } else {
  493. block_no = block_last->block_no + 1;
  494. block_last->block_next = p;
  495. p->block_prev = block_last;
  496. }
  497. block_last = &p[BLOCK_ALLOC - 1];
  498. /* ブロックを連結させる */
  499. for(i=0;i<BLOCK_ALLOC;i++) {
  500. if(i != 0) {
  501. p[i].block_prev = &p[i-1];
  502. }
  503. if(i != BLOCK_ALLOC -1) {
  504. p[i].block_next = &p[i+1];
  505. }
  506. p[i].block_no = block_no + i;
  507. }
  508. /* 未使用ブロックへのポインタを更新 */
  509. block_unused = &p[1];
  510. p->unit_size = 1;
  511. return p;
  512. }
  513. }
  514. static void block_free(struct block* p) {
  515. /* free() せずに、未使用フラグを付けるだけ */
  516. p->unit_size = 0;
  517. /* 未使用ポインターを更新する */
  518. if(block_unused == NULL) {
  519. block_unused = p;
  520. } else if(block_unused->block_no > p->block_no) {
  521. block_unused = p;
  522. }
  523. }
  524. unsigned int memmgr_usage (void)
  525. {
  526. return memmgr_usage_bytes / 1024;
  527. }
  528. #ifdef LOG_MEMMGR
  529. static char memmer_logfile[128];
  530. static FILE *log_fp;
  531. static void memmgr_log (char *buf)
  532. {
  533. if (!log_fp) {
  534. log_fp = fopen(memmer_logfile,"w");
  535. if (!log_fp) log_fp = stdout;
  536. fprintf(log_fp, "Memory manager: Memory leaks found.\n");
  537. }
  538. fprintf(log_fp, buf);
  539. return;
  540. }
  541. #endif
  542. static void memmgr_final (void)
  543. {
  544. struct block *block = block_first;
  545. struct chunk *chunk = chunk_first, *chunk2;
  546. struct unit_head_large *large = unit_head_large_first, *large2;
  547. int i;
  548. #ifdef LOG_MEMMGR
  549. int count = 0;
  550. char buf[128];
  551. #endif
  552. while (block) {
  553. if (block->unit_size) {
  554. for (i = 0; i < block->unit_count; i++) {
  555. struct unit_head *head = (struct unit_head*)(&block->data[block->unit_size * i]);
  556. if(head->block != NULL)
  557. {
  558. #ifdef LOG_MEMMGR
  559. sprintf (buf,
  560. "%04d : %s line %d size %d\n", ++count,
  561. head->file, head->line, head->size);
  562. memmgr_log (buf);
  563. #endif
  564. // get block pointer and free it [celest]
  565. _mfree ((char *)head + sizeof(struct unit_head) - sizeof(int), ALC_MARK);
  566. }
  567. }
  568. }
  569. //if (block->block_no >= block2->block_no + BLOCK_ALLOC - 1) {
  570. // reached a new block array
  571. //block = block->block_next;
  572. /* Okay wise guys... this is how block2 was allocated: [Skotlex]
  573. struct block* p;
  574. char *pb = (char *) CALLOC (sizeof(struct block),BLOCK_ALLOC + 1);
  575. pb += sizeof(struct block) - ((unsigned long)pb % sizeof(struct block));
  576. p = (struct block*)pb;
  577. The reason we get an invalid pointer is that we allocated pb, not p.
  578. So how do you get pb when you only have p?
  579. The answer is, you can't, because the original pointer was lost when
  580. memory-aligning the block. So we either forget this FREE or use a
  581. self-reference...
  582. Since we are already quitting, it might be ok to just not free the block
  583. as it is.
  584. */
  585. // didn't realise that before o.o -- block chunks are now freed below [celest]
  586. // FREE(block2);
  587. //block2 = block;
  588. //continue;
  589. //}
  590. block = block->block_next;
  591. }
  592. // free the allocated block chunks
  593. chunk = chunk_first;
  594. while (chunk) {
  595. chunk2 = chunk->next;
  596. FREE(chunk->block);
  597. FREE(chunk);
  598. chunk = chunk2;
  599. }
  600. while(large) {
  601. large2 = large->next;
  602. #ifdef LOG_MEMMGR
  603. sprintf (buf,
  604. "%04d : %s line %d size %d\n", ++count,
  605. large->unit_head.file, large->unit_head.line, large->unit_head.size);
  606. memmgr_log (buf);
  607. #endif
  608. FREE (large);
  609. large = large2;
  610. }
  611. #ifdef LOG_MEMMGR
  612. if(count == 0) {
  613. ShowInfo("Memory manager: No memory leaks found.\n");
  614. } else {
  615. ShowWarning("Memory manager: Memory leaks found and fixed.\n");
  616. fclose(log_fp);
  617. }
  618. #endif
  619. return;
  620. }
  621. static void memmgr_init (void)
  622. {
  623. #ifdef LOG_MEMMGR
  624. sprintf(memmer_logfile, "log/%s.leaks", SERVER_NAME);
  625. ShowStatus("Memory manager initialised: "CL_WHITE"%s"CL_RESET"\n", memmer_logfile);
  626. #endif
  627. return;
  628. }
  629. #endif
  630. /*======================================
  631. * Initialise
  632. *--------------------------------------
  633. */
  634. unsigned int malloc_usage (void)
  635. {
  636. #ifdef USE_MEMMGR
  637. return memmgr_usage ();
  638. #else
  639. return 0;
  640. #endif
  641. }
  642. void malloc_final (void)
  643. {
  644. #ifdef USE_MEMMGR
  645. memmgr_final ();
  646. #endif
  647. return;
  648. }
  649. void malloc_init (void)
  650. {
  651. #ifdef USE_MEMMGR
  652. memmgr_init ();
  653. #endif
  654. return;
  655. }