xmlmemory.c 23 KB

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