xmlmemory.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. /*
  2. * xmlmemory.c: libxml memory allocator wrapper.
  3. *
  4. * daniel@veillard.com
  5. */
  6. #define IN_LIBXML
  7. #include "libxml.h"
  8. #include <string.h>
  9. #ifdef HAVE_SYS_TYPES_H
  10. #include <sys/types.h>
  11. #endif
  12. #ifdef HAVE_TIME_H
  13. #include <time.h>
  14. #endif
  15. #ifdef HAVE_STDLIB_H
  16. #include <stdlib.h>
  17. #else
  18. #ifdef HAVE_MALLOC_H
  19. #include <malloc.h>
  20. #endif
  21. #endif
  22. #ifdef HAVE_CTYPE_H
  23. #include <ctype.h>
  24. #endif
  25. /* #define DEBUG_MEMORY */
  26. /**
  27. * MEM_LIST:
  28. *
  29. * keep track of all allocated blocks for error reporting
  30. * Always build the memory list !
  31. */
  32. #ifdef DEBUG_MEMORY_LOCATION
  33. #ifndef MEM_LIST
  34. #define MEM_LIST /* keep a list of all the allocated memory blocks */
  35. #endif
  36. #endif
  37. #include <libxml/globals.h> /* must come before xmlmemory.h */
  38. #include <libxml/xmlmemory.h>
  39. #include <libxml/xmlerror.h>
  40. #include <libxml/threads.h>
  41. static int xmlMemInitialized = 0;
  42. static unsigned long debugMemSize = 0;
  43. static unsigned long debugMemBlocks = 0;
  44. static unsigned long debugMaxMemSize = 0;
  45. static xmlMutexPtr xmlMemMutex = NULL;
  46. void xmlMallocBreakpoint(void);
  47. /************************************************************************
  48. * *
  49. * Macros, variables and associated types *
  50. * *
  51. ************************************************************************/
  52. #if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
  53. #ifdef xmlMalloc
  54. #undef xmlMalloc
  55. #endif
  56. #ifdef xmlRealloc
  57. #undef xmlRealloc
  58. #endif
  59. #ifdef xmlMemStrdup
  60. #undef xmlMemStrdup
  61. #endif
  62. #endif
  63. /*
  64. * Each of the blocks allocated begin with a header containing informations
  65. */
  66. #define MEMTAG 0x5aa5
  67. #define MALLOC_TYPE 1
  68. #define REALLOC_TYPE 2
  69. #define STRDUP_TYPE 3
  70. #define MALLOC_ATOMIC_TYPE 4
  71. #define REALLOC_ATOMIC_TYPE 5
  72. typedef struct memnod {
  73. unsigned int mh_tag;
  74. unsigned int mh_type;
  75. unsigned long mh_number;
  76. size_t mh_size;
  77. #ifdef MEM_LIST
  78. struct memnod *mh_next;
  79. struct memnod *mh_prev;
  80. #endif
  81. const char *mh_file;
  82. unsigned int mh_line;
  83. } MEMHDR;
  84. #ifdef SUN4
  85. #define ALIGN_SIZE 16
  86. #else
  87. #define ALIGN_SIZE sizeof(double)
  88. #endif
  89. #define HDR_SIZE sizeof(MEMHDR)
  90. #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
  91. / ALIGN_SIZE ) * ALIGN_SIZE)
  92. #define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
  93. #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
  94. static unsigned int block=0;
  95. static unsigned int xmlMemStopAtBlock = 0;
  96. static void *xmlMemTraceBlockAt = NULL;
  97. #ifdef MEM_LIST
  98. static MEMHDR *memlist = NULL;
  99. #endif
  100. static void debugmem_tag_error(void *addr);
  101. #ifdef MEM_LIST
  102. static void debugmem_list_add(MEMHDR *);
  103. static void debugmem_list_delete(MEMHDR *);
  104. #endif
  105. #define Mem_Tag_Err(a) debugmem_tag_error(a);
  106. #ifndef TEST_POINT
  107. #define TEST_POINT
  108. #endif
  109. /**
  110. * xmlMallocBreakpoint:
  111. *
  112. * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
  113. * number reaches the specified value this function is called. One need to add a breakpoint
  114. * to it to get the context in which the given block is allocated.
  115. */
  116. void
  117. xmlMallocBreakpoint(void) {
  118. xmlGenericError(xmlGenericErrorContext,
  119. "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
  120. }
  121. /**
  122. * xmlMallocLoc:
  123. * @size: an int specifying the size in byte to allocate.
  124. * @file: the file name or NULL
  125. * @line: the line number
  126. *
  127. * a malloc() equivalent, with logging of the allocation info.
  128. *
  129. * Returns a pointer to the allocated area or NULL in case of lack of memory.
  130. */
  131. void *
  132. xmlMallocLoc(size_t size, const char * file, int line)
  133. {
  134. MEMHDR *p;
  135. void *ret;
  136. if (!xmlMemInitialized) xmlInitMemory();
  137. #ifdef DEBUG_MEMORY
  138. xmlGenericError(xmlGenericErrorContext,
  139. "Malloc(%d)\n",size);
  140. #endif
  141. TEST_POINT
  142. p = (MEMHDR *) malloc(RESERVE_SIZE+size);
  143. if (!p) {
  144. xmlGenericError(xmlGenericErrorContext,
  145. "xmlMallocLoc : Out of free space\n");
  146. xmlMemoryDump();
  147. return(NULL);
  148. }
  149. p->mh_tag = MEMTAG;
  150. p->mh_size = size;
  151. p->mh_type = MALLOC_TYPE;
  152. p->mh_file = file;
  153. p->mh_line = line;
  154. xmlMutexLock(xmlMemMutex);
  155. p->mh_number = ++block;
  156. debugMemSize += size;
  157. debugMemBlocks++;
  158. if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
  159. #ifdef MEM_LIST
  160. debugmem_list_add(p);
  161. #endif
  162. xmlMutexUnlock(xmlMemMutex);
  163. #ifdef DEBUG_MEMORY
  164. xmlGenericError(xmlGenericErrorContext,
  165. "Malloc(%d) Ok\n",size);
  166. #endif
  167. if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
  168. ret = HDR_2_CLIENT(p);
  169. if (xmlMemTraceBlockAt == ret) {
  170. xmlGenericError(xmlGenericErrorContext,
  171. "%p : Malloc(%ld) Ok\n", xmlMemTraceBlockAt, size);
  172. xmlMallocBreakpoint();
  173. }
  174. TEST_POINT
  175. return(ret);
  176. }
  177. /**
  178. * xmlMallocAtomicLoc:
  179. * @size: an int specifying the size in byte to allocate.
  180. * @file: the file name or NULL
  181. * @line: the line number
  182. *
  183. * a malloc() equivalent, with logging of the allocation info.
  184. *
  185. * Returns a pointer to the allocated area or NULL in case of lack of memory.
  186. */
  187. void *
  188. xmlMallocAtomicLoc(size_t size, const char * file, int line)
  189. {
  190. MEMHDR *p;
  191. void *ret;
  192. if (!xmlMemInitialized) xmlInitMemory();
  193. #ifdef DEBUG_MEMORY
  194. xmlGenericError(xmlGenericErrorContext,
  195. "Malloc(%d)\n",size);
  196. #endif
  197. TEST_POINT
  198. p = (MEMHDR *) malloc(RESERVE_SIZE+size);
  199. if (!p) {
  200. xmlGenericError(xmlGenericErrorContext,
  201. "xmlMallocLoc : Out of free space\n");
  202. xmlMemoryDump();
  203. return(NULL);
  204. }
  205. p->mh_tag = MEMTAG;
  206. p->mh_size = size;
  207. p->mh_type = MALLOC_ATOMIC_TYPE;
  208. p->mh_file = file;
  209. p->mh_line = line;
  210. xmlMutexLock(xmlMemMutex);
  211. p->mh_number = ++block;
  212. debugMemSize += size;
  213. debugMemBlocks++;
  214. if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
  215. #ifdef MEM_LIST
  216. debugmem_list_add(p);
  217. #endif
  218. xmlMutexUnlock(xmlMemMutex);
  219. #ifdef DEBUG_MEMORY
  220. xmlGenericError(xmlGenericErrorContext,
  221. "Malloc(%d) Ok\n",size);
  222. #endif
  223. if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
  224. ret = HDR_2_CLIENT(p);
  225. if (xmlMemTraceBlockAt == ret) {
  226. xmlGenericError(xmlGenericErrorContext,
  227. "%p : Malloc(%ld) Ok\n", xmlMemTraceBlockAt, size);
  228. xmlMallocBreakpoint();
  229. }
  230. TEST_POINT
  231. return(ret);
  232. }
  233. /**
  234. * xmlMemMalloc:
  235. * @size: an int specifying the size in byte to allocate.
  236. *
  237. * a malloc() equivalent, with logging of the allocation info.
  238. *
  239. * Returns a pointer to the allocated area or NULL in case of lack of memory.
  240. */
  241. void *
  242. xmlMemMalloc(size_t size)
  243. {
  244. return(xmlMallocLoc(size, "none", 0));
  245. }
  246. /**
  247. * xmlReallocLoc:
  248. * @ptr: the initial memory block pointer
  249. * @size: an int specifying the size in byte to allocate.
  250. * @file: the file name or NULL
  251. * @line: the line number
  252. *
  253. * a realloc() equivalent, with logging of the allocation info.
  254. *
  255. * Returns a pointer to the allocated area or NULL in case of lack of memory.
  256. */
  257. void *
  258. xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
  259. {
  260. MEMHDR *p;
  261. unsigned long number;
  262. #ifdef DEBUG_MEMORY
  263. size_t oldsize;
  264. #endif
  265. if (ptr == NULL)
  266. return(xmlMallocLoc(size, file, line));
  267. if (!xmlMemInitialized) xmlInitMemory();
  268. TEST_POINT
  269. p = CLIENT_2_HDR(ptr);
  270. number = p->mh_number;
  271. if (xmlMemStopAtBlock == number) xmlMallocBreakpoint();
  272. if (p->mh_tag != MEMTAG) {
  273. Mem_Tag_Err(p);
  274. goto error;
  275. }
  276. p->mh_tag = ~MEMTAG;
  277. xmlMutexLock(xmlMemMutex);
  278. debugMemSize -= p->mh_size;
  279. debugMemBlocks--;
  280. #ifdef DEBUG_MEMORY
  281. oldsize = p->mh_size;
  282. #endif
  283. #ifdef MEM_LIST
  284. debugmem_list_delete(p);
  285. #endif
  286. xmlMutexUnlock(xmlMemMutex);
  287. p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
  288. if (!p) {
  289. goto error;
  290. }
  291. if (xmlMemTraceBlockAt == ptr) {
  292. xmlGenericError(xmlGenericErrorContext,
  293. "%p : Realloced(%ld -> %ld) Ok\n",
  294. xmlMemTraceBlockAt, p->mh_size, size);
  295. xmlMallocBreakpoint();
  296. }
  297. p->mh_tag = MEMTAG;
  298. p->mh_number = number;
  299. p->mh_type = REALLOC_TYPE;
  300. p->mh_size = size;
  301. p->mh_file = file;
  302. p->mh_line = line;
  303. xmlMutexLock(xmlMemMutex);
  304. debugMemSize += size;
  305. debugMemBlocks++;
  306. if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
  307. #ifdef MEM_LIST
  308. debugmem_list_add(p);
  309. #endif
  310. xmlMutexUnlock(xmlMemMutex);
  311. TEST_POINT
  312. #ifdef DEBUG_MEMORY
  313. xmlGenericError(xmlGenericErrorContext,
  314. "Realloced(%d to %d) Ok\n", oldsize, size);
  315. #endif
  316. return(HDR_2_CLIENT(p));
  317. error:
  318. return(NULL);
  319. }
  320. /**
  321. * xmlMemRealloc:
  322. * @ptr: the initial memory block pointer
  323. * @size: an int specifying the size in byte to allocate.
  324. *
  325. * a realloc() equivalent, with logging of the allocation info.
  326. *
  327. * Returns a pointer to the allocated area or NULL in case of lack of memory.
  328. */
  329. void *
  330. xmlMemRealloc(void *ptr,size_t size) {
  331. return(xmlReallocLoc(ptr, size, "none", 0));
  332. }
  333. /**
  334. * xmlMemFree:
  335. * @ptr: the memory block pointer
  336. *
  337. * a free() equivalent, with error checking.
  338. */
  339. void
  340. xmlMemFree(void *ptr)
  341. {
  342. MEMHDR *p;
  343. char *target;
  344. #ifdef DEBUG_MEMORY
  345. size_t size;
  346. #endif
  347. if (ptr == NULL)
  348. return;
  349. if (ptr == (void *) -1) {
  350. xmlGenericError(xmlGenericErrorContext,
  351. "trying to free pointer from freed area\n");
  352. goto error;
  353. }
  354. if (xmlMemTraceBlockAt == ptr) {
  355. xmlGenericError(xmlGenericErrorContext,
  356. "%p : Freed()\n", xmlMemTraceBlockAt);
  357. xmlMallocBreakpoint();
  358. }
  359. TEST_POINT
  360. target = (char *) ptr;
  361. p = CLIENT_2_HDR(ptr);
  362. if (p->mh_tag != MEMTAG) {
  363. Mem_Tag_Err(p);
  364. goto error;
  365. }
  366. if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
  367. p->mh_tag = ~MEMTAG;
  368. memset(target, -1, p->mh_size);
  369. xmlMutexLock(xmlMemMutex);
  370. debugMemSize -= p->mh_size;
  371. debugMemBlocks--;
  372. #ifdef DEBUG_MEMORY
  373. size = p->mh_size;
  374. #endif
  375. #ifdef MEM_LIST
  376. debugmem_list_delete(p);
  377. #endif
  378. xmlMutexUnlock(xmlMemMutex);
  379. free(p);
  380. TEST_POINT
  381. #ifdef DEBUG_MEMORY
  382. xmlGenericError(xmlGenericErrorContext,
  383. "Freed(%d) Ok\n", size);
  384. #endif
  385. return;
  386. error:
  387. xmlGenericError(xmlGenericErrorContext,
  388. "xmlMemFree(%lX) error\n", (unsigned long) ptr);
  389. xmlMallocBreakpoint();
  390. return;
  391. }
  392. /**
  393. * xmlMemStrdupLoc:
  394. * @str: the initial string pointer
  395. * @file: the file name or NULL
  396. * @line: the line number
  397. *
  398. * a strdup() equivalent, with logging of the allocation info.
  399. *
  400. * Returns a pointer to the new string or NULL if allocation error occurred.
  401. */
  402. char *
  403. xmlMemStrdupLoc(const char *str, const char *file, int line)
  404. {
  405. char *s;
  406. size_t size = strlen(str) + 1;
  407. MEMHDR *p;
  408. if (!xmlMemInitialized) xmlInitMemory();
  409. TEST_POINT
  410. p = (MEMHDR *) malloc(RESERVE_SIZE+size);
  411. if (!p) {
  412. goto error;
  413. }
  414. p->mh_tag = MEMTAG;
  415. p->mh_size = size;
  416. p->mh_type = STRDUP_TYPE;
  417. p->mh_file = file;
  418. p->mh_line = line;
  419. xmlMutexLock(xmlMemMutex);
  420. p->mh_number = ++block;
  421. debugMemSize += size;
  422. debugMemBlocks++;
  423. if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
  424. #ifdef MEM_LIST
  425. debugmem_list_add(p);
  426. #endif
  427. xmlMutexUnlock(xmlMemMutex);
  428. s = (char *) HDR_2_CLIENT(p);
  429. if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
  430. if (s != NULL)
  431. strcpy(s,str);
  432. else
  433. goto error;
  434. TEST_POINT
  435. if (xmlMemTraceBlockAt == s) {
  436. xmlGenericError(xmlGenericErrorContext,
  437. "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
  438. xmlMallocBreakpoint();
  439. }
  440. return(s);
  441. error:
  442. return(NULL);
  443. }
  444. /**
  445. * xmlMemoryStrdup:
  446. * @str: the initial string pointer
  447. *
  448. * a strdup() equivalent, with logging of the allocation info.
  449. *
  450. * Returns a pointer to the new string or NULL if allocation error occurred.
  451. */
  452. char *
  453. xmlMemoryStrdup(const char *str) {
  454. return(xmlMemStrdupLoc(str, "none", 0));
  455. }
  456. /**
  457. * xmlMemUsed:
  458. *
  459. * Provides the amount of memory currently allocated
  460. *
  461. * Returns an int representing the amount of memory allocated.
  462. */
  463. int
  464. xmlMemUsed(void) {
  465. return(debugMemSize);
  466. }
  467. /**
  468. * xmlMemBlocks:
  469. *
  470. * Provides the number of memory areas currently allocated
  471. *
  472. * Returns an int representing the number of blocks
  473. */
  474. int
  475. xmlMemBlocks(void) {
  476. return(debugMemBlocks);
  477. }
  478. #ifdef MEM_LIST
  479. /**
  480. * xmlMemContentShow:
  481. * @fp: a FILE descriptor used as the output file
  482. * @p: a memory block header
  483. *
  484. * tries to show some content from the memory block
  485. */
  486. static void
  487. xmlMemContentShow(FILE *fp, MEMHDR *p)
  488. {
  489. int i,j,k,len = p->mh_size;
  490. const char *buf = (const char *) HDR_2_CLIENT(p);
  491. if (p == NULL) {
  492. fprintf(fp, " NULL");
  493. return;
  494. }
  495. for (i = 0;i < len;i++) {
  496. if (buf[i] == 0) break;
  497. if (!isprint((unsigned char) buf[i])) break;
  498. }
  499. if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
  500. if (len >= 4) {
  501. MEMHDR *q;
  502. void *cur;
  503. for (j = 0;(j < len -3) && (j < 40);j += 4) {
  504. cur = *((void **) &buf[j]);
  505. q = CLIENT_2_HDR(cur);
  506. p = memlist;
  507. k = 0;
  508. while (p != NULL) {
  509. if (p == q) break;
  510. p = p->mh_next;
  511. if (k++ > 100) break;
  512. }
  513. if ((p != NULL) && (p == q)) {
  514. fprintf(fp, " pointer to #%lu at index %d",
  515. p->mh_number, j);
  516. return;
  517. }
  518. }
  519. }
  520. } else if ((i == 0) && (buf[i] == 0)) {
  521. fprintf(fp," null");
  522. } else {
  523. if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
  524. else {
  525. fprintf(fp," [");
  526. for (j = 0;j < i;j++)
  527. fprintf(fp,"%c", buf[j]);
  528. fprintf(fp,"]");
  529. }
  530. }
  531. }
  532. #endif
  533. /**
  534. * xmlMemDisplayLast:
  535. * @fp: a FILE descriptor used as the output file, if NULL, the result is
  536. * written to the file .memorylist
  537. * @nbBytes: the amount of memory to dump
  538. *
  539. * the last nbBytes of memory allocated and not freed, useful for dumping
  540. * the memory left allocated between two places at runtime.
  541. */
  542. void
  543. xmlMemDisplayLast(FILE *fp, long nbBytes)
  544. {
  545. #ifdef MEM_LIST
  546. MEMHDR *p;
  547. unsigned idx;
  548. int nb = 0;
  549. #endif
  550. FILE *old_fp = fp;
  551. if (nbBytes <= 0)
  552. return;
  553. if (fp == NULL) {
  554. fp = fopen(".memorylist", "w");
  555. if (fp == NULL)
  556. return;
  557. }
  558. #ifdef MEM_LIST
  559. fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
  560. nbBytes, debugMemSize, debugMaxMemSize);
  561. fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
  562. idx = 0;
  563. xmlMutexLock(xmlMemMutex);
  564. p = memlist;
  565. while ((p) && (nbBytes > 0)) {
  566. fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
  567. (unsigned long)p->mh_size);
  568. switch (p->mh_type) {
  569. case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
  570. case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
  571. case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
  572. case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
  573. case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
  574. default:
  575. fprintf(fp,"Unknown memory block, may be corrupted");
  576. xmlMutexUnlock(xmlMemMutex);
  577. if (old_fp == NULL)
  578. fclose(fp);
  579. return;
  580. }
  581. if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
  582. if (p->mh_tag != MEMTAG)
  583. fprintf(fp," INVALID");
  584. nb++;
  585. if (nb < 100)
  586. xmlMemContentShow(fp, p);
  587. else
  588. fprintf(fp," skip");
  589. fprintf(fp,"\n");
  590. nbBytes -= (unsigned long)p->mh_size;
  591. p = p->mh_next;
  592. }
  593. xmlMutexUnlock(xmlMemMutex);
  594. #else
  595. fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
  596. #endif
  597. if (old_fp == NULL)
  598. fclose(fp);
  599. }
  600. /**
  601. * xmlMemDisplay:
  602. * @fp: a FILE descriptor used as the output file, if NULL, the result is
  603. * written to the file .memorylist
  604. *
  605. * show in-extenso the memory blocks allocated
  606. */
  607. void
  608. xmlMemDisplay(FILE *fp)
  609. {
  610. #ifdef MEM_LIST
  611. MEMHDR *p;
  612. unsigned idx;
  613. int nb = 0;
  614. #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
  615. time_t currentTime;
  616. char buf[500];
  617. struct tm * tstruct;
  618. #endif
  619. #endif
  620. FILE *old_fp = fp;
  621. if (fp == NULL) {
  622. fp = fopen(".memorylist", "w");
  623. if (fp == NULL)
  624. return;
  625. }
  626. #ifdef MEM_LIST
  627. #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
  628. currentTime = time(NULL);
  629. tstruct = localtime(&currentTime);
  630. strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
  631. fprintf(fp," %s\n\n", buf);
  632. #endif
  633. fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
  634. debugMemSize, debugMaxMemSize);
  635. fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
  636. idx = 0;
  637. xmlMutexLock(xmlMemMutex);
  638. p = memlist;
  639. while (p) {
  640. fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
  641. (unsigned long)p->mh_size);
  642. switch (p->mh_type) {
  643. case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
  644. case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
  645. case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
  646. case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
  647. case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
  648. default:
  649. fprintf(fp,"Unknown memory block, may be corrupted");
  650. xmlMutexUnlock(xmlMemMutex);
  651. if (old_fp == NULL)
  652. fclose(fp);
  653. return;
  654. }
  655. if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
  656. if (p->mh_tag != MEMTAG)
  657. fprintf(fp," INVALID");
  658. nb++;
  659. if (nb < 100)
  660. xmlMemContentShow(fp, p);
  661. else
  662. fprintf(fp," skip");
  663. fprintf(fp,"\n");
  664. p = p->mh_next;
  665. }
  666. xmlMutexUnlock(xmlMemMutex);
  667. #else
  668. fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
  669. #endif
  670. if (old_fp == NULL)
  671. fclose(fp);
  672. }
  673. #ifdef MEM_LIST
  674. static void debugmem_list_add(MEMHDR *p)
  675. {
  676. p->mh_next = memlist;
  677. p->mh_prev = NULL;
  678. if (memlist) memlist->mh_prev = p;
  679. memlist = p;
  680. #ifdef MEM_LIST_DEBUG
  681. if (stderr)
  682. Mem_Display(stderr);
  683. #endif
  684. }
  685. static void debugmem_list_delete(MEMHDR *p)
  686. {
  687. if (p->mh_next)
  688. p->mh_next->mh_prev = p->mh_prev;
  689. if (p->mh_prev)
  690. p->mh_prev->mh_next = p->mh_next;
  691. else memlist = p->mh_next;
  692. #ifdef MEM_LIST_DEBUG
  693. if (stderr)
  694. Mem_Display(stderr);
  695. #endif
  696. }
  697. #endif
  698. /*
  699. * debugmem_tag_error:
  700. *
  701. * internal error function.
  702. */
  703. static void debugmem_tag_error(void *p)
  704. {
  705. xmlGenericError(xmlGenericErrorContext,
  706. "Memory tag error occurs :%p \n\t bye\n", p);
  707. #ifdef MEM_LIST
  708. if (stderr)
  709. xmlMemDisplay(stderr);
  710. #endif
  711. }
  712. #ifdef MEM_LIST
  713. static FILE *xmlMemoryDumpFile = NULL;
  714. #endif
  715. /**
  716. * xmlMemShow:
  717. * @fp: a FILE descriptor used as the output file
  718. * @nr: number of entries to dump
  719. *
  720. * show a show display of the memory allocated, and dump
  721. * the @nr last allocated areas which were not freed
  722. */
  723. void
  724. xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
  725. {
  726. #ifdef MEM_LIST
  727. MEMHDR *p;
  728. #endif
  729. if (fp != NULL)
  730. fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
  731. debugMemSize, debugMaxMemSize);
  732. #ifdef MEM_LIST
  733. xmlMutexLock(xmlMemMutex);
  734. if (nr > 0) {
  735. fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
  736. p = memlist;
  737. while ((p) && nr > 0) {
  738. fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
  739. switch (p->mh_type) {
  740. case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
  741. case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
  742. case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
  743. case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
  744. case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
  745. default:fprintf(fp," ??? in ");break;
  746. }
  747. if (p->mh_file != NULL)
  748. fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
  749. if (p->mh_tag != MEMTAG)
  750. fprintf(fp," INVALID");
  751. xmlMemContentShow(fp, p);
  752. fprintf(fp,"\n");
  753. nr--;
  754. p = p->mh_next;
  755. }
  756. }
  757. xmlMutexUnlock(xmlMemMutex);
  758. #endif /* MEM_LIST */
  759. }
  760. /**
  761. * xmlMemoryDump:
  762. *
  763. * Dump in-extenso the memory blocks allocated to the file .memorylist
  764. */
  765. void
  766. xmlMemoryDump(void)
  767. {
  768. #ifdef MEM_LIST
  769. FILE *dump;
  770. if (debugMaxMemSize == 0)
  771. return;
  772. dump = fopen(".memdump", "w");
  773. if (dump == NULL)
  774. xmlMemoryDumpFile = stderr;
  775. else xmlMemoryDumpFile = dump;
  776. xmlMemDisplay(xmlMemoryDumpFile);
  777. if (dump != NULL) fclose(dump);
  778. #endif /* MEM_LIST */
  779. }
  780. /****************************************************************
  781. * *
  782. * Initialization Routines *
  783. * *
  784. ****************************************************************/
  785. /**
  786. * xmlInitMemory:
  787. *
  788. * Initialize the memory layer.
  789. *
  790. * Returns 0 on success
  791. */
  792. int
  793. xmlInitMemory(void)
  794. {
  795. #ifdef HAVE_STDLIB_H
  796. char *breakpoint;
  797. #endif
  798. #ifdef DEBUG_MEMORY
  799. xmlGenericError(xmlGenericErrorContext,
  800. "xmlInitMemory()\n");
  801. #endif
  802. /*
  803. This is really not good code (see Bug 130419). Suggestions for
  804. improvement will be welcome!
  805. */
  806. if (xmlMemInitialized) return(-1);
  807. xmlMemInitialized = 1;
  808. xmlMemMutex = xmlNewMutex();
  809. #ifdef HAVE_STDLIB_H
  810. breakpoint = getenv("XML_MEM_BREAKPOINT");
  811. if (breakpoint != NULL) {
  812. sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
  813. }
  814. #endif
  815. #ifdef HAVE_STDLIB_H
  816. breakpoint = getenv("XML_MEM_TRACE");
  817. if (breakpoint != NULL) {
  818. sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
  819. }
  820. #endif
  821. #ifdef DEBUG_MEMORY
  822. xmlGenericError(xmlGenericErrorContext,
  823. "xmlInitMemory() Ok\n");
  824. #endif
  825. return(0);
  826. }
  827. /**
  828. * xmlCleanupMemory:
  829. *
  830. * Free up all the memory allocated by the library for its own
  831. * use. This should not be called by user level code.
  832. */
  833. void
  834. xmlCleanupMemory(void) {
  835. #ifdef DEBUG_MEMORY
  836. xmlGenericError(xmlGenericErrorContext,
  837. "xmlCleanupMemory()\n");
  838. #endif
  839. if (xmlMemInitialized == 0)
  840. return;
  841. xmlFreeMutex(xmlMemMutex);
  842. xmlMemMutex = NULL;
  843. xmlMemInitialized = 0;
  844. #ifdef DEBUG_MEMORY
  845. xmlGenericError(xmlGenericErrorContext,
  846. "xmlCleanupMemory() Ok\n");
  847. #endif
  848. }
  849. /**
  850. * xmlMemSetup:
  851. * @freeFunc: the free() function to use
  852. * @mallocFunc: the malloc() function to use
  853. * @reallocFunc: the realloc() function to use
  854. * @strdupFunc: the strdup() function to use
  855. *
  856. * Override the default memory access functions with a new set
  857. * This has to be called before any other libxml routines !
  858. *
  859. * Should this be blocked if there was already some allocations
  860. * done ?
  861. *
  862. * Returns 0 on success
  863. */
  864. int
  865. xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
  866. xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
  867. #ifdef DEBUG_MEMORY
  868. xmlGenericError(xmlGenericErrorContext,
  869. "xmlMemSetup()\n");
  870. #endif
  871. if (freeFunc == NULL)
  872. return(-1);
  873. if (mallocFunc == NULL)
  874. return(-1);
  875. if (reallocFunc == NULL)
  876. return(-1);
  877. if (strdupFunc == NULL)
  878. return(-1);
  879. xmlFree = freeFunc;
  880. xmlMalloc = mallocFunc;
  881. xmlMallocAtomic = mallocFunc;
  882. xmlRealloc = reallocFunc;
  883. xmlMemStrdup = strdupFunc;
  884. #ifdef DEBUG_MEMORY
  885. xmlGenericError(xmlGenericErrorContext,
  886. "xmlMemSetup() Ok\n");
  887. #endif
  888. return(0);
  889. }
  890. /**
  891. * xmlMemGet:
  892. * @freeFunc: place to save the free() function in use
  893. * @mallocFunc: place to save the malloc() function in use
  894. * @reallocFunc: place to save the realloc() function in use
  895. * @strdupFunc: place to save the strdup() function in use
  896. *
  897. * Provides the memory access functions set currently in use
  898. *
  899. * Returns 0 on success
  900. */
  901. int
  902. xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
  903. xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
  904. if (freeFunc != NULL) *freeFunc = xmlFree;
  905. if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
  906. if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
  907. if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
  908. return(0);
  909. }
  910. /**
  911. * xmlGcMemSetup:
  912. * @freeFunc: the free() function to use
  913. * @mallocFunc: the malloc() function to use
  914. * @mallocAtomicFunc: the malloc() function to use for atomic allocations
  915. * @reallocFunc: the realloc() function to use
  916. * @strdupFunc: the strdup() function to use
  917. *
  918. * Override the default memory access functions with a new set
  919. * This has to be called before any other libxml routines !
  920. * The mallocAtomicFunc is specialized for atomic block
  921. * allocations (i.e. of areas useful for garbage collected memory allocators
  922. *
  923. * Should this be blocked if there was already some allocations
  924. * done ?
  925. *
  926. * Returns 0 on success
  927. */
  928. int
  929. xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
  930. xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
  931. xmlStrdupFunc strdupFunc) {
  932. #ifdef DEBUG_MEMORY
  933. xmlGenericError(xmlGenericErrorContext,
  934. "xmlGcMemSetup()\n");
  935. #endif
  936. if (freeFunc == NULL)
  937. return(-1);
  938. if (mallocFunc == NULL)
  939. return(-1);
  940. if (mallocAtomicFunc == NULL)
  941. return(-1);
  942. if (reallocFunc == NULL)
  943. return(-1);
  944. if (strdupFunc == NULL)
  945. return(-1);
  946. xmlFree = freeFunc;
  947. xmlMalloc = mallocFunc;
  948. xmlMallocAtomic = mallocAtomicFunc;
  949. xmlRealloc = reallocFunc;
  950. xmlMemStrdup = strdupFunc;
  951. #ifdef DEBUG_MEMORY
  952. xmlGenericError(xmlGenericErrorContext,
  953. "xmlGcMemSetup() Ok\n");
  954. #endif
  955. return(0);
  956. }
  957. /**
  958. * xmlGcMemGet:
  959. * @freeFunc: place to save the free() function in use
  960. * @mallocFunc: place to save the malloc() function in use
  961. * @mallocAtomicFunc: place to save the atomic malloc() function in use
  962. * @reallocFunc: place to save the realloc() function in use
  963. * @strdupFunc: place to save the strdup() function in use
  964. *
  965. * Provides the memory access functions set currently in use
  966. * The mallocAtomicFunc is specialized for atomic block
  967. * allocations (i.e. of areas useful for garbage collected memory allocators
  968. *
  969. * Returns 0 on success
  970. */
  971. int
  972. xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
  973. xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
  974. xmlStrdupFunc *strdupFunc) {
  975. if (freeFunc != NULL) *freeFunc = xmlFree;
  976. if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
  977. if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
  978. if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
  979. if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
  980. return(0);
  981. }
  982. #define bottom_xmlmemory
  983. #include "elfgcchack.h"