xmlmemory.c 26 KB

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