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