xref: /aosp_15_r20/external/cronet/third_party/libxml/src/xmlmemory.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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(&currentTime);
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