malloc.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717
  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. * ズを持つブロック同士もリンクリスト(samesize_prev,samesize_nect) でつな
  119. * がっています。それにより、不要となったメモリの再利用が効率的に行えます。
  120. */
  121. /* ブロックに入るデータ量 */
  122. #define BLOCK_DATA_SIZE 80*1024
  123. /* 一度に確保するブロックの数。 */
  124. #define BLOCK_ALLOC 32
  125. /* ブロックのアライメント */
  126. #define BLOCK_ALIGNMENT 64
  127. /* ブロック */
  128. struct block {
  129. int block_no; /* ブロック番号 */
  130. struct block* block_prev; /* 前に確保した領域 */
  131. struct block* block_next; /* 次に確保した領域 */
  132. int samesize_no; /* 同じサイズの番号 */
  133. struct block* samesize_prev; /* 同じサイズの前の領域 */
  134. struct block* samesize_next; /* 同じサイズの次の領域 */
  135. size_t unit_size; /* ユニットのバイト数 0=未使用 */
  136. size_t unit_hash; /* ユニットのハッシュ */
  137. int unit_count; /* ユニットの数 */
  138. int unit_used; /* 使用済みユニット */
  139. char data[BLOCK_DATA_SIZE];
  140. };
  141. struct unit_head {
  142. struct block* block;
  143. size_t size;
  144. const char* file;
  145. int line;
  146. unsigned int checksum;
  147. };
  148. struct chunk {
  149. char *block;
  150. struct chunk *next;
  151. };
  152. static struct block* block_first = NULL;
  153. static struct block* block_last = NULL;
  154. static struct block* block_unused = NULL;
  155. /* ユニットへのハッシュ。80KB/64Byte = 1280個 */
  156. static struct block* unit_first[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 最初 */
  157. static struct block* unit_unfill[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 埋まってない */
  158. static struct block* unit_last[BLOCK_DATA_SIZE/BLOCK_ALIGNMENT]; /* 最後 */
  159. /* メモリを使い回せない領域用のデータ */
  160. struct unit_head_large {
  161. struct unit_head_large* prev;
  162. struct unit_head_large* next;
  163. struct unit_head unit_head;
  164. };
  165. static struct unit_head_large *unit_head_large_first = NULL;
  166. static struct chunk *chunk_first = NULL;
  167. static struct block* block_malloc(void);
  168. static void block_free(struct block* p);
  169. static void memmgr_info(void);
  170. static unsigned int memmgr_usage_bytes = 0;
  171. void* _mmalloc(size_t size, const char *file, int line, const char *func )
  172. {
  173. int i;
  174. struct block *block;
  175. size_t size_hash;
  176. if (((long) size) < 0) {
  177. ShowError("_mmalloc: %d\n", size);
  178. return 0;
  179. }
  180. size_hash = (size+BLOCK_ALIGNMENT-1) / BLOCK_ALIGNMENT;
  181. if(size == 0) {
  182. return NULL;
  183. }
  184. memmgr_usage_bytes += size;
  185. /* ブロック長を超える領域の確保には、malloc() を用いる */
  186. /* その際、unit_head.block に NULL を代入して区別する */
  187. if(size_hash * BLOCK_ALIGNMENT > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
  188. struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func);
  189. if(p != NULL) {
  190. p->unit_head.block = NULL;
  191. p->unit_head.size = size;
  192. p->unit_head.file = file;
  193. p->unit_head.line = line;
  194. p->prev = NULL;
  195. if (unit_head_large_first == NULL)
  196. p->next = NULL;
  197. else {
  198. unit_head_large_first->prev = p;
  199. p->next = unit_head_large_first;
  200. }
  201. unit_head_large_first = p;
  202. #ifdef DEBUG_MEMMGR
  203. // set allocated data to 0xCD (clean memory)
  204. memset((char *)p + sizeof(struct unit_head_large) - sizeof(int), 0xCD, size);
  205. #endif
  206. *(int*)((char*)p + sizeof(struct unit_head_large) - sizeof(int) + size) = 0xdeadbeaf;
  207. return (char *)p + sizeof(struct unit_head_large) - sizeof(int);
  208. } else {
  209. ShowFatalError("Memory manager::memmgr_alloc failed (allocating %d+%d bytes at %s:%d).\n", sizeof(struct unit_head_large), size, file, line);
  210. exit(EXIT_FAILURE);
  211. }
  212. }
  213. /* 同一サイズのブロックが確保されていない時、新たに確保する */
  214. if(unit_unfill[size_hash] == NULL) {
  215. block = block_malloc();
  216. if(unit_first[size_hash] == NULL) {
  217. /* 初回確保 */
  218. unit_first[size_hash] = block;
  219. unit_last[size_hash] = block;
  220. block->samesize_no = 0;
  221. block->samesize_prev = NULL;
  222. block->samesize_next = NULL;
  223. } else {
  224. /* 連結作業 */
  225. unit_last[size_hash]->samesize_next = block;
  226. block->samesize_no = unit_last[size_hash]->samesize_no + 1;
  227. block->samesize_prev = unit_last[size_hash];
  228. block->samesize_next = NULL;
  229. unit_last[size_hash] = block;
  230. }
  231. unit_unfill[size_hash] = block;
  232. block->unit_size = size_hash * BLOCK_ALIGNMENT + sizeof(struct unit_head);
  233. block->unit_count = (int)(BLOCK_DATA_SIZE / block->unit_size);
  234. block->unit_used = 0;
  235. block->unit_hash = size_hash;
  236. /* 未使用Flagを立てる */
  237. for(i=0;i<block->unit_count;i++) {
  238. ((struct unit_head*)(&block->data[block->unit_size * i]))->block = NULL;
  239. }
  240. }
  241. /* ユニット使用個数加算 */
  242. block = unit_unfill[size_hash];
  243. block->unit_used++;
  244. /* ユニット内を全て使い果たした */
  245. if(block->unit_count == block->unit_used) {
  246. do {
  247. unit_unfill[size_hash] = unit_unfill[size_hash]->samesize_next;
  248. } while(
  249. unit_unfill[size_hash] != NULL &&
  250. unit_unfill[size_hash]->unit_count == unit_unfill[size_hash]->unit_used
  251. );
  252. }
  253. /* ブロックの中の空きユニット捜索 */
  254. for(i=0;i<block->unit_count;i++) {
  255. struct unit_head *head = (struct unit_head*)(&block->data[block->unit_size * i]);
  256. if(head->block == NULL) {
  257. head->block = block;
  258. head->size = size;
  259. head->line = line;
  260. head->file = file;
  261. #ifdef DEBUG_MEMMGR
  262. // set allocated memory to 0xCD (clean memory)
  263. memset((char *)head + sizeof(struct unit_head) - sizeof(int), 0xCD, size);
  264. #endif
  265. *(int*)((char*)head + sizeof(struct unit_head) - sizeof(int) + size) = 0xdeadbeaf;
  266. return (char *)head + sizeof(struct unit_head) - sizeof(int);
  267. }
  268. }
  269. // ここに来てはいけない。
  270. ShowFatalError("Memory manager::memmgr_malloc() serious error (allocating %d+%d bytes at %s:%d)\n", sizeof(struct unit_head_large), size, file, line);
  271. memmgr_info();
  272. exit(EXIT_FAILURE);
  273. //return NULL;
  274. };
  275. void* _mcalloc(size_t num, size_t size, const char *file, int line, const char *func )
  276. {
  277. void *p = _mmalloc(num * size,file,line,func);
  278. memset(p,0,num * size);
  279. return p;
  280. }
  281. void* _mrealloc(void *memblock, size_t size, const char *file, int line, const char *func )
  282. {
  283. size_t old_size;
  284. if(memblock == NULL) {
  285. return _mmalloc(size,file,line,func);
  286. }
  287. old_size = ((struct unit_head *)((char *)memblock - sizeof(struct unit_head) + sizeof(int)))->size;
  288. if(old_size > size) {
  289. // サイズ縮小 -> そのまま返す(手抜き)
  290. return memblock;
  291. } else {
  292. // サイズ拡大
  293. void *p = _mmalloc(size,file,line,func);
  294. if(p != NULL) {
  295. memcpy(p,memblock,old_size);
  296. }
  297. _mfree(memblock,file,line,func);
  298. return p;
  299. }
  300. }
  301. char* _mstrdup(const char *p, const char *file, int line, const char *func )
  302. {
  303. if(p == NULL) {
  304. return NULL;
  305. } else {
  306. size_t len = strlen(p);
  307. char *string = (char *)_mmalloc(len + 1,file,line,func);
  308. memcpy(string,p,len+1);
  309. return string;
  310. }
  311. }
  312. void _mfree(void *ptr, const char *file, int line, const char *func )
  313. {
  314. struct unit_head *head;
  315. size_t size_hash;
  316. if (ptr == NULL)
  317. return;
  318. head = (struct unit_head *)((char *)ptr - sizeof(struct unit_head) + sizeof(int));
  319. size_hash = (head->size+BLOCK_ALIGNMENT-1) / BLOCK_ALIGNMENT;
  320. if(head->block == NULL) {
  321. if(size_hash * BLOCK_ALIGNMENT > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
  322. /* malloc() で直に確保された領域 */
  323. struct unit_head_large *head_large = (struct unit_head_large *)((char *)ptr - sizeof(struct unit_head_large) + sizeof(int));
  324. if(
  325. *(int*)((char*)head_large + sizeof(struct unit_head_large) - sizeof(int) + head->size)
  326. != 0xdeadbeaf)
  327. {
  328. ShowError("Memory manager: args of aFree is overflowed pointer %s line %d\n", file, line);
  329. }
  330. if(head_large->prev) {
  331. head_large->prev->next = head_large->next;
  332. } else {
  333. unit_head_large_first = head_large->next;
  334. }
  335. if(head_large->next) {
  336. head_large->next->prev = head_large->prev;
  337. }
  338. head->block = NULL;
  339. memmgr_usage_bytes -= head->size;
  340. #ifdef DEBUG_MEMMGR
  341. // set freed memory to 0xDD (dead memory)
  342. memset(ptr, 0xDD, head->size);
  343. #endif
  344. FREE(head_large,file,line,func);
  345. } else {
  346. ShowError("Memory manager: args of aFree is freed pointer %s:%d@%s\n", file, line, func);
  347. }
  348. ptr = NULL;
  349. return;
  350. } else {
  351. /* ユニット解放 */
  352. struct block *block = head->block;
  353. if((unsigned long)block % sizeof(struct block) != 0) {
  354. ShowError("Memory manager: args of aFree is not valid pointer %s line %d\n", file, line);
  355. } else if(*(int*)((char*)head + sizeof(struct unit_head) - sizeof(int) + head->size) != 0xdeadbeaf) {
  356. ShowError("Memory manager: args of aFree is overflowed pointer %s line %d\n", file, line);
  357. } else {
  358. head->block = NULL;
  359. #ifdef DEBUG_MEMMGR
  360. // set freed memory to 0xDD (dead memory)
  361. memset(ptr, 0xDD, head->size);
  362. #endif
  363. memmgr_usage_bytes -= head->size;
  364. if(--block->unit_used == 0) {
  365. /* ブロックの解放 */
  366. if(unit_unfill[block->unit_hash] == block) {
  367. /* 空きユニットに指定されている */
  368. do {
  369. unit_unfill[block->unit_hash] = unit_unfill[block->unit_hash]->samesize_next;
  370. } while(
  371. unit_unfill[block->unit_hash] != NULL &&
  372. unit_unfill[block->unit_hash]->unit_count == unit_unfill[block->unit_hash]->unit_used
  373. );
  374. }
  375. if(block->samesize_prev == NULL && block->samesize_next == NULL) {
  376. /* 独立ブロックの解放 */
  377. unit_first[block->unit_hash] = NULL;
  378. unit_last[block->unit_hash] = NULL;
  379. unit_unfill[block->unit_hash] = NULL;
  380. } else if(block->samesize_prev == NULL) {
  381. /* 先頭ブロックの解放 */
  382. unit_first[block->unit_hash] = block->samesize_next;
  383. (block->samesize_next)->samesize_prev = NULL;
  384. } else if(block->samesize_next == NULL) {
  385. /* 末端ブロックの解放 */
  386. unit_last[block->unit_hash] = block->samesize_prev;
  387. (block->samesize_prev)->samesize_next = NULL;
  388. } else {
  389. /* 中間ブロックの解放 */
  390. (block->samesize_next)->samesize_prev = block->samesize_prev;
  391. (block->samesize_prev)->samesize_next = block->samesize_next;
  392. }
  393. block_free(block);
  394. } else {
  395. /* 空きユニットの再設定 */
  396. if(
  397. unit_unfill[block->unit_hash] == NULL ||
  398. unit_unfill[block->unit_hash]->samesize_no > block->samesize_no
  399. ) {
  400. unit_unfill[block->unit_hash] = block;
  401. }
  402. }
  403. ptr = NULL;
  404. }
  405. }
  406. }
  407. /* 現在の状況を表示する */
  408. static void memmgr_info(void)
  409. {
  410. int i;
  411. struct block *p;
  412. ShowInfo("** Memory Manager Information **\n");
  413. if(block_first == NULL) {
  414. ShowMessage("Uninitialized.\n");
  415. return;
  416. }
  417. ShowMessage(
  418. "Blocks: %04u , BlockSize: %06u Byte , Used: %08uKB\n",
  419. block_last->block_no+1,sizeof(struct block),
  420. (block_last->block_no+1) * sizeof(struct block) / 1024
  421. );
  422. p = block_first;
  423. for(i=0;i<=block_last->block_no;i++) {
  424. ShowMessage(" Block #%04u : ",p->block_no);
  425. if(p->unit_size == 0) {
  426. ShowMessage("unused.\n");
  427. } else {
  428. ShowMessage(
  429. "size: %05u byte. used: %04u/%04u prev:",
  430. p->unit_size - sizeof(struct unit_head),p->unit_used,p->unit_count
  431. );
  432. if(p->samesize_prev == NULL) {
  433. ShowMessage("NULL");
  434. } else {
  435. ShowMessage("%04u",(p->samesize_prev)->block_no);
  436. }
  437. ShowMessage(" next:");
  438. if(p->samesize_next == NULL) {
  439. ShowMessage("NULL");
  440. } else {
  441. ShowMessage("%04u",(p->samesize_next)->block_no);
  442. }
  443. ShowMessage("\n");
  444. }
  445. p = p->block_next;
  446. }
  447. }
  448. /* ブロックを確保する */
  449. static struct block* block_malloc(void)
  450. {
  451. if(block_unused != NULL) {
  452. /* ブロック用の領域は確保済み */
  453. struct block* ret = block_unused;
  454. do {
  455. block_unused = block_unused->block_next;
  456. } while(block_unused != NULL && block_unused->unit_size != 0);
  457. return ret;
  458. } else {
  459. /* ブロック用の領域を新たに確保する */
  460. int i;
  461. int block_no;
  462. struct block* p;
  463. struct chunk* chunk;
  464. char *pb = (char *)CALLOC(sizeof(struct block),BLOCK_ALLOC+1,file,line,func);
  465. if(pb == NULL) {
  466. ShowFatalError("Memory manager::block_alloc failed.\n");
  467. exit(EXIT_FAILURE);
  468. }
  469. // store original block address in chunk
  470. chunk = (struct chunk *)MALLOC(sizeof(struct chunk),file,line,func);
  471. if (chunk == NULL) {
  472. ShowFatalError("Memory manager::block_alloc failed.\n");
  473. exit(EXIT_FAILURE);
  474. }
  475. chunk->block = pb;
  476. chunk->next = (chunk_first) ? chunk_first : NULL;
  477. chunk_first = chunk;
  478. // ブロックのポインタの先頭をsizeof(block) アライメントに揃える
  479. // このアドレスをfree() することはないので、直接ポインタを変更している。
  480. pb += sizeof(struct block) - ((unsigned long)pb % sizeof(struct block));
  481. p = (struct block*)pb;
  482. if(block_first == NULL) {
  483. /* 初回確保 */
  484. block_no = 0;
  485. block_first = p;
  486. } else {
  487. block_no = block_last->block_no + 1;
  488. block_last->block_next = p;
  489. p->block_prev = block_last;
  490. }
  491. block_last = &p[BLOCK_ALLOC - 1];
  492. /* ブロックを連結させる */
  493. for(i=0;i<BLOCK_ALLOC;i++) {
  494. if(i != 0) {
  495. p[i].block_prev = &p[i-1];
  496. }
  497. if(i != BLOCK_ALLOC -1) {
  498. p[i].block_next = &p[i+1];
  499. }
  500. p[i].block_no = block_no + i;
  501. }
  502. /* 未使用ブロックへのポインタを更新 */
  503. block_unused = &p[1];
  504. p->unit_size = 1;
  505. return p;
  506. }
  507. }
  508. static void block_free(struct block* p)
  509. {
  510. /* free() せずに、未使用フラグを付けるだけ */
  511. p->unit_size = 0;
  512. /* 未使用ポインターを更新する */
  513. if(block_unused == NULL) {
  514. block_unused = p;
  515. } else if(block_unused->block_no > p->block_no) {
  516. block_unused = p;
  517. }
  518. }
  519. unsigned int memmgr_usage (void)
  520. {
  521. return memmgr_usage_bytes / 1024;
  522. }
  523. #ifdef LOG_MEMMGR
  524. static char memmer_logfile[128];
  525. static FILE *log_fp;
  526. static void memmgr_log (char *buf)
  527. {
  528. time_t raw;
  529. struct tm* t;
  530. if( !log_fp )
  531. {
  532. log_fp = fopen(memmer_logfile,"w");
  533. if (!log_fp) log_fp = stdout;
  534. fprintf(log_fp, "Memory manager: Memory leaks found (Revision %s).\n", get_svn_revision());
  535. }
  536. time(&raw);
  537. t = localtime(&raw);
  538. fprintf(log_fp, "%04d%02d%02d%02d%02d%02d %s", (t->tm_year+1900), (t->tm_mon+1), t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, buf);
  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 %lu\n", ++count,
  561. head->file, head->line, (unsigned long)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,file,line,func);
  597. FREE(chunk,file,line,func);
  598. chunk = chunk2;
  599. }
  600. while(large) {
  601. large2 = large->next;
  602. #ifdef LOG_MEMMGR
  603. sprintf (buf,
  604. "%04d : %s line %d size %lu\n", ++count,
  605. large->unit_head.file, large->unit_head.line, (unsigned long)large->unit_head.size);
  606. memmgr_log (buf);
  607. #endif
  608. FREE(large,file,line,func);
  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. }