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