xmlmemory.c 26 KB

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