1 /* libxml2 - Library for parsing XML documents
2  * Copyright (C) 2006-2019 Free Software Foundation, Inc.
3  *
4  * This file is not part of the GNU gettext program, but is used with
5  * GNU gettext.
6  *
7  * The original copyright notice is as follows:
8  */
9 
10 /*
11  * Copyright (C) 1998-2012 Daniel Veillard.  All Rights Reserved.
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a copy
14  * of this software and associated documentation files (the "Software"), to deal
15  * in the Software without restriction, including without limitation the rights
16  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17  * copies of the Software, and to permit persons to whom the Software is fur-
18  * nished to do so, subject to the following conditions:
19  *
20  * The above copyright notice and this permission notice shall be included in
21  * all copies or substantial portions of the Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FIT-
25  * NESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29  * THE SOFTWARE.
30  *
31  * daniel@veillard.com
32  */
33 
34 /*
35  * xmlmemory.c:  libxml memory allocator wrapper.
36  */
37 
38 #define IN_LIBXML
39 #include "libxml.h"
40 
41 #include <string.h>
42 
43 #ifdef HAVE_SYS_TYPES_H
44 #include <sys/types.h>
45 #endif
46 
47 #ifdef HAVE_TIME_H
48 #include <time.h>
49 #endif
50 
51 #ifdef HAVE_STDLIB_H
52 #include <stdlib.h>
53 #else
54 #ifdef HAVE_MALLOC_H
55 #include <malloc.h>
56 #endif
57 #endif
58 
59 #ifdef HAVE_CTYPE_H
60 #include <ctype.h>
61 #endif
62 
63 /* #define DEBUG_MEMORY */
64 
65 /**
66  * MEM_LIST:
67  *
68  * keep track of all allocated blocks for error reporting
69  * Always build the memory list !
70  */
71 #ifdef DEBUG_MEMORY_LOCATION
72 #ifndef MEM_LIST
73 #define MEM_LIST /* keep a list of all the allocated memory blocks */
74 #endif
75 #endif
76 
77 #include <libxml/globals.h>	/* must come before xmlmemory.h */
78 #include <libxml/xmlmemory.h>
79 #include <libxml/xmlerror.h>
80 #include <libxml/threads.h>
81 
82 static int xmlMemInitialized = 0;
83 static unsigned long  debugMemSize = 0;
84 static unsigned long  debugMemBlocks = 0;
85 static unsigned long  debugMaxMemSize = 0;
86 static xmlMutexPtr xmlMemMutex = NULL;
87 
88 void xmlMallocBreakpoint(void);
89 
90 /************************************************************************
91  *									*
92  *		Macros, variables and associated types			*
93  *									*
94  ************************************************************************/
95 
96 #if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED) && !defined IN_LIBTEXTSTYLE
97 #ifdef xmlMalloc
98 #undef xmlMalloc
99 #endif
100 #ifdef xmlRealloc
101 #undef xmlRealloc
102 #endif
103 #ifdef xmlMemStrdup
104 #undef xmlMemStrdup
105 #endif
106 #endif
107 
108 /*
109  * Each of the blocks allocated begin with a header containing informations
110  */
111 
112 #define MEMTAG 0x5aa5
113 
114 #define MALLOC_TYPE 1
115 #define REALLOC_TYPE 2
116 #define STRDUP_TYPE 3
117 #define MALLOC_ATOMIC_TYPE 4
118 #define REALLOC_ATOMIC_TYPE 5
119 
120 typedef struct memnod {
121     unsigned int   mh_tag;
122     unsigned int   mh_type;
123     unsigned long  mh_number;
124     size_t         mh_size;
125 #ifdef MEM_LIST
126    struct memnod *mh_next;
127    struct memnod *mh_prev;
128 #endif
129    const char    *mh_file;
130    unsigned int   mh_line;
131 }  MEMHDR;
132 
133 
134 #ifdef SUN4
135 #define ALIGN_SIZE  16
136 #else
137 #define ALIGN_SIZE  sizeof(double)
138 #endif
139 #define HDR_SIZE    sizeof(MEMHDR)
140 #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
141 		      / ALIGN_SIZE ) * ALIGN_SIZE)
142 
143 #define MAX_SIZE_T ((size_t)-1)
144 
145 #define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE))
146 #define HDR_2_CLIENT(a)    ((void *) (((char *) (a)) + RESERVE_SIZE))
147 
148 
149 static unsigned int block=0;
150 static unsigned int xmlMemStopAtBlock = 0;
151 static void *xmlMemTraceBlockAt = NULL;
152 #ifdef MEM_LIST
153 static MEMHDR *memlist = NULL;
154 #endif
155 
156 static void debugmem_tag_error(void *addr);
157 #ifdef MEM_LIST
158 static void  debugmem_list_add(MEMHDR *);
159 static void debugmem_list_delete(MEMHDR *);
160 #endif
161 #define Mem_Tag_Err(a) debugmem_tag_error(a);
162 
163 #ifndef TEST_POINT
164 #define TEST_POINT
165 #endif
166 
167 /**
168  * xmlMallocBreakpoint:
169  *
170  * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
171  * number reaches the specified value this function is called. One need to add a breakpoint
172  * to it to get the context in which the given block is allocated.
173  */
174 
175 void
xmlMallocBreakpoint(void)176 xmlMallocBreakpoint(void) {
177     xmlGenericError(xmlGenericErrorContext,
178 	    "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
179 }
180 
181 /**
182  * xmlMallocLoc:
183  * @size:  an int specifying the size in byte to allocate.
184  * @file:  the file name or NULL
185  * @line:  the line number
186  *
187  * a malloc() equivalent, with logging of the allocation info.
188  *
189  * Returns a pointer to the allocated area or NULL in case of lack of memory.
190  */
191 
192 void *
xmlMallocLoc(size_t size,const char * file,int line)193 xmlMallocLoc(size_t size, const char * file, int line)
194 {
195     MEMHDR *p;
196     void *ret;
197 
198     if (!xmlMemInitialized) xmlInitMemory();
199 #ifdef DEBUG_MEMORY
200     xmlGenericError(xmlGenericErrorContext,
201 	    "Malloc(%d)\n",size);
202 #endif
203 
204     TEST_POINT
205 
206     if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
207 	xmlGenericError(xmlGenericErrorContext,
208 		"xmlMallocLoc : Unsigned overflow\n");
209 	xmlMemoryDump();
210 	return(NULL);
211     }
212 
213     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
214 
215     if (!p) {
216 	xmlGenericError(xmlGenericErrorContext,
217 		"xmlMallocLoc : Out of free space\n");
218 	xmlMemoryDump();
219 	return(NULL);
220     }
221     p->mh_tag = MEMTAG;
222     p->mh_size = size;
223     p->mh_type = MALLOC_TYPE;
224     p->mh_file = file;
225     p->mh_line = line;
226     xmlMutexLock(xmlMemMutex);
227     p->mh_number = ++block;
228     debugMemSize += size;
229     debugMemBlocks++;
230     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
231 #ifdef MEM_LIST
232     debugmem_list_add(p);
233 #endif
234     xmlMutexUnlock(xmlMemMutex);
235 
236 #ifdef DEBUG_MEMORY
237     xmlGenericError(xmlGenericErrorContext,
238 	    "Malloc(%d) Ok\n",size);
239 #endif
240 
241     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
242 
243     ret = HDR_2_CLIENT(p);
244 
245     if (xmlMemTraceBlockAt == ret) {
246 	xmlGenericError(xmlGenericErrorContext,
247 			"%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
248 			(long unsigned)size);
249 	xmlMallocBreakpoint();
250     }
251 
252     TEST_POINT
253 
254     return(ret);
255 }
256 
257 /**
258  * xmlMallocAtomicLoc:
259  * @size:  an unsigned int specifying the size in byte to allocate.
260  * @file:  the file name or NULL
261  * @line:  the line number
262  *
263  * a malloc() equivalent, with logging of the allocation info.
264  *
265  * Returns a pointer to the allocated area or NULL in case of lack of memory.
266  */
267 
268 void *
xmlMallocAtomicLoc(size_t size,const char * file,int line)269 xmlMallocAtomicLoc(size_t size, const char * file, int line)
270 {
271     MEMHDR *p;
272     void *ret;
273 
274     if (!xmlMemInitialized) xmlInitMemory();
275 #ifdef DEBUG_MEMORY
276     xmlGenericError(xmlGenericErrorContext,
277 	    "Malloc(%d)\n",size);
278 #endif
279 
280     TEST_POINT
281 
282     if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
283 	xmlGenericError(xmlGenericErrorContext,
284 		"xmlMallocAtomicLoc : Unsigned overflow\n");
285 	xmlMemoryDump();
286 	return(NULL);
287     }
288 
289     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
290 
291     if (!p) {
292 	xmlGenericError(xmlGenericErrorContext,
293 		"xmlMallocAtomicLoc : Out of free space\n");
294 	xmlMemoryDump();
295 	return(NULL);
296     }
297     p->mh_tag = MEMTAG;
298     p->mh_size = size;
299     p->mh_type = MALLOC_ATOMIC_TYPE;
300     p->mh_file = file;
301     p->mh_line = line;
302     xmlMutexLock(xmlMemMutex);
303     p->mh_number = ++block;
304     debugMemSize += size;
305     debugMemBlocks++;
306     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
307 #ifdef MEM_LIST
308     debugmem_list_add(p);
309 #endif
310     xmlMutexUnlock(xmlMemMutex);
311 
312 #ifdef DEBUG_MEMORY
313     xmlGenericError(xmlGenericErrorContext,
314 	    "Malloc(%d) Ok\n",size);
315 #endif
316 
317     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
318 
319     ret = HDR_2_CLIENT(p);
320 
321     if (xmlMemTraceBlockAt == ret) {
322 	xmlGenericError(xmlGenericErrorContext,
323 			"%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
324 			(long unsigned)size);
325 	xmlMallocBreakpoint();
326     }
327 
328     TEST_POINT
329 
330     return(ret);
331 }
332 /**
333  * xmlMemMalloc:
334  * @size:  an int specifying the size in byte to allocate.
335  *
336  * a malloc() equivalent, with logging of the allocation info.
337  *
338  * Returns a pointer to the allocated area or NULL in case of lack of memory.
339  */
340 
341 void *
xmlMemMalloc(size_t size)342 xmlMemMalloc(size_t size)
343 {
344     return(xmlMallocLoc(size, "none", 0));
345 }
346 
347 /**
348  * xmlReallocLoc:
349  * @ptr:  the initial memory block pointer
350  * @size:  an int specifying the size in byte to allocate.
351  * @file:  the file name or NULL
352  * @line:  the line number
353  *
354  * a realloc() equivalent, with logging of the allocation info.
355  *
356  * Returns a pointer to the allocated area or NULL in case of lack of memory.
357  */
358 
359 void *
xmlReallocLoc(void * ptr,size_t size,const char * file,int line)360 xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
361 {
362     MEMHDR *p, *tmp;
363     unsigned long number;
364 #ifdef DEBUG_MEMORY
365     size_t oldsize;
366 #endif
367 
368     if (ptr == NULL)
369         return(xmlMallocLoc(size, file, line));
370 
371     if (!xmlMemInitialized) xmlInitMemory();
372     TEST_POINT
373 
374     p = CLIENT_2_HDR(ptr);
375     number = p->mh_number;
376     if (xmlMemStopAtBlock == number) xmlMallocBreakpoint();
377     if (p->mh_tag != MEMTAG) {
378        Mem_Tag_Err(p);
379 	 goto error;
380     }
381     p->mh_tag = ~MEMTAG;
382     xmlMutexLock(xmlMemMutex);
383     debugMemSize -= p->mh_size;
384     debugMemBlocks--;
385 #ifdef DEBUG_MEMORY
386     oldsize = p->mh_size;
387 #endif
388 #ifdef MEM_LIST
389     debugmem_list_delete(p);
390 #endif
391     xmlMutexUnlock(xmlMemMutex);
392 
393     if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
394 	xmlGenericError(xmlGenericErrorContext,
395 		"xmlReallocLoc : Unsigned overflow\n");
396 	xmlMemoryDump();
397 	return(NULL);
398     }
399 
400     tmp = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
401     if (!tmp) {
402 	 free(p);
403 	 goto error;
404     }
405     p = tmp;
406     if (xmlMemTraceBlockAt == ptr) {
407 	xmlGenericError(xmlGenericErrorContext,
408 			"%p : Realloced(%lu -> %lu) Ok\n",
409 			xmlMemTraceBlockAt, (long unsigned)p->mh_size,
410 			(long unsigned)size);
411 	xmlMallocBreakpoint();
412     }
413     p->mh_tag = MEMTAG;
414     p->mh_number = number;
415     p->mh_type = REALLOC_TYPE;
416     p->mh_size = size;
417     p->mh_file = file;
418     p->mh_line = line;
419     xmlMutexLock(xmlMemMutex);
420     debugMemSize += size;
421     debugMemBlocks++;
422     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
423 #ifdef MEM_LIST
424     debugmem_list_add(p);
425 #endif
426     xmlMutexUnlock(xmlMemMutex);
427 
428     TEST_POINT
429 
430 #ifdef DEBUG_MEMORY
431     xmlGenericError(xmlGenericErrorContext,
432 	    "Realloced(%d to %d) Ok\n", oldsize, size);
433 #endif
434     return(HDR_2_CLIENT(p));
435 
436 error:
437     return(NULL);
438 }
439 
440 /**
441  * xmlMemRealloc:
442  * @ptr:  the initial memory block pointer
443  * @size:  an int specifying the size in byte to allocate.
444  *
445  * a realloc() equivalent, with logging of the allocation info.
446  *
447  * Returns a pointer to the allocated area or NULL in case of lack of memory.
448  */
449 
450 void *
xmlMemRealloc(void * ptr,size_t size)451 xmlMemRealloc(void *ptr,size_t size) {
452     return(xmlReallocLoc(ptr, size, "none", 0));
453 }
454 
455 /**
456  * xmlMemFree:
457  * @ptr:  the memory block pointer
458  *
459  * a free() equivalent, with error checking.
460  */
461 void
xmlMemFree(void * ptr)462 xmlMemFree(void *ptr)
463 {
464     MEMHDR *p;
465     char *target;
466 #ifdef DEBUG_MEMORY
467     size_t size;
468 #endif
469 
470     if (ptr == NULL)
471 	return;
472 
473     if (ptr == (void *) -1) {
474 	xmlGenericError(xmlGenericErrorContext,
475 	    "trying to free pointer from freed area\n");
476         goto error;
477     }
478 
479     if (xmlMemTraceBlockAt == ptr) {
480 	xmlGenericError(xmlGenericErrorContext,
481 			"%p : Freed()\n", xmlMemTraceBlockAt);
482 	xmlMallocBreakpoint();
483     }
484 
485     TEST_POINT
486 
487     target = (char *) ptr;
488 
489     p = CLIENT_2_HDR(ptr);
490     if (p->mh_tag != MEMTAG) {
491         Mem_Tag_Err(p);
492         goto error;
493     }
494     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
495     p->mh_tag = ~MEMTAG;
496     memset(target, -1, p->mh_size);
497     xmlMutexLock(xmlMemMutex);
498     debugMemSize -= p->mh_size;
499     debugMemBlocks--;
500 #ifdef DEBUG_MEMORY
501     size = p->mh_size;
502 #endif
503 #ifdef MEM_LIST
504     debugmem_list_delete(p);
505 #endif
506     xmlMutexUnlock(xmlMemMutex);
507 
508     free(p);
509 
510     TEST_POINT
511 
512 #ifdef DEBUG_MEMORY
513     xmlGenericError(xmlGenericErrorContext,
514 	    "Freed(%d) Ok\n", size);
515 #endif
516 
517     return;
518 
519 error:
520     xmlGenericError(xmlGenericErrorContext,
521 	    "xmlMemFree(%p) error\n", ptr);
522     xmlMallocBreakpoint();
523     return;
524 }
525 
526 /**
527  * xmlMemStrdupLoc:
528  * @str:  the initial string pointer
529  * @file:  the file name or NULL
530  * @line:  the line number
531  *
532  * a strdup() equivalent, with logging of the allocation info.
533  *
534  * Returns a pointer to the new string or NULL if allocation error occurred.
535  */
536 
537 char *
xmlMemStrdupLoc(const char * str,const char * file,int line)538 xmlMemStrdupLoc(const char *str, const char *file, int line)
539 {
540     char *s;
541     size_t size = strlen(str) + 1;
542     MEMHDR *p;
543 
544     if (!xmlMemInitialized) xmlInitMemory();
545     TEST_POINT
546 
547     if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
548 	xmlGenericError(xmlGenericErrorContext,
549 		"xmlMemStrdupLoc : Unsigned overflow\n");
550 	xmlMemoryDump();
551 	return(NULL);
552     }
553 
554     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
555     if (!p) {
556       goto error;
557     }
558     p->mh_tag = MEMTAG;
559     p->mh_size = size;
560     p->mh_type = STRDUP_TYPE;
561     p->mh_file = file;
562     p->mh_line = line;
563     xmlMutexLock(xmlMemMutex);
564     p->mh_number = ++block;
565     debugMemSize += size;
566     debugMemBlocks++;
567     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
568 #ifdef MEM_LIST
569     debugmem_list_add(p);
570 #endif
571     xmlMutexUnlock(xmlMemMutex);
572 
573     s = (char *) HDR_2_CLIENT(p);
574 
575     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
576 
577     strcpy(s,str);
578 
579     TEST_POINT
580 
581     if (xmlMemTraceBlockAt == s) {
582 	xmlGenericError(xmlGenericErrorContext,
583 			"%p : Strdup() Ok\n", xmlMemTraceBlockAt);
584 	xmlMallocBreakpoint();
585     }
586 
587     return(s);
588 
589 error:
590     return(NULL);
591 }
592 
593 /**
594  * xmlMemoryStrdup:
595  * @str:  the initial string pointer
596  *
597  * a strdup() equivalent, with logging of the allocation info.
598  *
599  * Returns a pointer to the new string or NULL if allocation error occurred.
600  */
601 
602 char *
xmlMemoryStrdup(const char * str)603 xmlMemoryStrdup(const char *str) {
604     return(xmlMemStrdupLoc(str, "none", 0));
605 }
606 
607 /**
608  * xmlMemUsed:
609  *
610  * Provides the amount of memory currently allocated
611  *
612  * Returns an int representing the amount of memory allocated.
613  */
614 
615 int
xmlMemUsed(void)616 xmlMemUsed(void) {
617     int res;
618 
619     xmlMutexLock(xmlMemMutex);
620     res = debugMemSize;
621     xmlMutexUnlock(xmlMemMutex);
622     return(res);
623 }
624 
625 /**
626  * xmlMemBlocks:
627  *
628  * Provides the number of memory areas currently allocated
629  *
630  * Returns an int representing the number of blocks
631  */
632 
633 int
xmlMemBlocks(void)634 xmlMemBlocks(void) {
635     int res;
636 
637     xmlMutexLock(xmlMemMutex);
638     res = debugMemBlocks;
639     xmlMutexUnlock(xmlMemMutex);
640     return(res);
641 }
642 
643 #ifdef MEM_LIST
644 /**
645  * xmlMemContentShow:
646  * @fp:  a FILE descriptor used as the output file
647  * @p:  a memory block header
648  *
649  * tries to show some content from the memory block
650  */
651 
652 static void
xmlMemContentShow(FILE * fp,MEMHDR * p)653 xmlMemContentShow(FILE *fp, MEMHDR *p)
654 {
655     int i,j,k,len;
656     const char *buf;
657 
658     if (p == NULL) {
659 	fprintf(fp, " NULL");
660 	return;
661     }
662     len = p->mh_size;
663     buf = (const char *) HDR_2_CLIENT(p);
664 
665     for (i = 0;i < len;i++) {
666         if (buf[i] == 0) break;
667 	if (!isprint((unsigned char) buf[i])) break;
668     }
669     if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
670         if (len >= 4) {
671 	    MEMHDR *q;
672 	    void *cur;
673 
674             for (j = 0;(j < len -3) && (j < 40);j += 4) {
675 		cur = *((void **) &buf[j]);
676 		q = CLIENT_2_HDR(cur);
677 		p = memlist;
678 		k = 0;
679 		while (p != NULL) {
680 		    if (p == q) break;
681 		    p = p->mh_next;
682 		    if (k++ > 100) break;
683 		}
684 		if ((p != NULL) && (p == q)) {
685 		    fprintf(fp, " pointer to #%lu at index %d",
686 		            p->mh_number, j);
687 		    return;
688 		}
689 	    }
690 	}
691     } else if ((i == 0) && (buf[i] == 0)) {
692         fprintf(fp," null");
693     } else {
694         if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
695 	else {
696             fprintf(fp," [");
697 	    for (j = 0;j < i;j++)
698                 fprintf(fp,"%c", buf[j]);
699             fprintf(fp,"]");
700 	}
701     }
702 }
703 #endif
704 
705 /**
706  * xmlMemDisplayLast:
707  * @fp:  a FILE descriptor used as the output file, if NULL, the result is
708  *       written to the file .memorylist
709  * @nbBytes: the amount of memory to dump
710  *
711  * the last nbBytes of memory allocated and not freed, useful for dumping
712  * the memory left allocated between two places at runtime.
713  */
714 
715 void
xmlMemDisplayLast(FILE * fp,long nbBytes)716 xmlMemDisplayLast(FILE *fp, long nbBytes)
717 {
718 #ifdef MEM_LIST
719     MEMHDR *p;
720     unsigned idx;
721     int     nb = 0;
722 #endif
723     FILE *old_fp = fp;
724 
725     if (nbBytes <= 0)
726         return;
727 
728     if (fp == NULL) {
729 	fp = fopen(".memorylist", "w");
730 	if (fp == NULL)
731 	    return;
732     }
733 
734 #ifdef MEM_LIST
735     fprintf(fp,"   Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
736             nbBytes, debugMemSize, debugMaxMemSize);
737     fprintf(fp,"BLOCK  NUMBER   SIZE  TYPE\n");
738     idx = 0;
739     xmlMutexLock(xmlMemMutex);
740     p = memlist;
741     while ((p) && (nbBytes > 0)) {
742 	  fprintf(fp,"%-5u  %6lu %6lu ",idx++,p->mh_number,
743 		  (unsigned long)p->mh_size);
744         switch (p->mh_type) {
745            case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
746            case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
747            case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
748            case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
749            case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
750            default:
751 	        fprintf(fp,"Unknown memory block, may be corrupted");
752 		xmlMutexUnlock(xmlMemMutex);
753 		if (old_fp == NULL)
754 		    fclose(fp);
755 		return;
756         }
757 	if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
758         if (p->mh_tag != MEMTAG)
759 	      fprintf(fp,"  INVALID");
760         nb++;
761 	if (nb < 100)
762 	    xmlMemContentShow(fp, p);
763 	else
764 	    fprintf(fp," skip");
765 
766         fprintf(fp,"\n");
767 	nbBytes -= (unsigned long)p->mh_size;
768         p = p->mh_next;
769     }
770     xmlMutexUnlock(xmlMemMutex);
771 #else
772     fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
773 #endif
774     if (old_fp == NULL)
775 	fclose(fp);
776 }
777 
778 /**
779  * xmlMemDisplay:
780  * @fp:  a FILE descriptor used as the output file, if NULL, the result is
781  *       written to the file .memorylist
782  *
783  * show in-extenso the memory blocks allocated
784  */
785 
786 void
xmlMemDisplay(FILE * fp)787 xmlMemDisplay(FILE *fp)
788 {
789 #ifdef MEM_LIST
790     MEMHDR *p;
791     unsigned idx;
792     int     nb = 0;
793 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
794     time_t currentTime;
795     char buf[500];
796     struct tm * tstruct;
797 #endif
798 #endif
799     FILE *old_fp = fp;
800 
801     if (fp == NULL) {
802 	fp = fopen(".memorylist", "w");
803 	if (fp == NULL)
804 	    return;
805     }
806 
807 #ifdef MEM_LIST
808 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
809     currentTime = time(NULL);
810     tstruct = localtime(&currentTime);
811     strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
812     fprintf(fp,"      %s\n\n", buf);
813 #endif
814 
815 
816     fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
817             debugMemSize, debugMaxMemSize);
818     fprintf(fp,"BLOCK  NUMBER   SIZE  TYPE\n");
819     idx = 0;
820     xmlMutexLock(xmlMemMutex);
821     p = memlist;
822     while (p) {
823 	  fprintf(fp,"%-5u  %6lu %6lu ",idx++,p->mh_number,
824 		  (unsigned long)p->mh_size);
825         switch (p->mh_type) {
826            case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
827            case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
828            case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
829            case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
830            case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
831            default:
832 	        fprintf(fp,"Unknown memory block, may be corrupted");
833 		xmlMutexUnlock(xmlMemMutex);
834 		if (old_fp == NULL)
835 		    fclose(fp);
836 		return;
837         }
838 	if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
839         if (p->mh_tag != MEMTAG)
840 	      fprintf(fp,"  INVALID");
841         nb++;
842 	if (nb < 100)
843 	    xmlMemContentShow(fp, p);
844 	else
845 	    fprintf(fp," skip");
846 
847         fprintf(fp,"\n");
848         p = p->mh_next;
849     }
850     xmlMutexUnlock(xmlMemMutex);
851 #else
852     fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
853 #endif
854     if (old_fp == NULL)
855 	fclose(fp);
856 }
857 
858 #ifdef MEM_LIST
859 
debugmem_list_add(MEMHDR * p)860 static void debugmem_list_add(MEMHDR *p)
861 {
862      p->mh_next = memlist;
863      p->mh_prev = NULL;
864      if (memlist) memlist->mh_prev = p;
865      memlist = p;
866 #ifdef MEM_LIST_DEBUG
867      if (stderr)
868      Mem_Display(stderr);
869 #endif
870 }
871 
debugmem_list_delete(MEMHDR * p)872 static void debugmem_list_delete(MEMHDR *p)
873 {
874      if (p->mh_next)
875      p->mh_next->mh_prev = p->mh_prev;
876      if (p->mh_prev)
877      p->mh_prev->mh_next = p->mh_next;
878      else memlist = p->mh_next;
879 #ifdef MEM_LIST_DEBUG
880      if (stderr)
881      Mem_Display(stderr);
882 #endif
883 }
884 
885 #endif
886 
887 /*
888  * debugmem_tag_error:
889  *
890  * internal error function.
891  */
892 
debugmem_tag_error(void * p)893 static void debugmem_tag_error(void *p)
894 {
895      xmlGenericError(xmlGenericErrorContext,
896 	     "Memory tag error occurs :%p \n\t bye\n", p);
897 #ifdef MEM_LIST
898      if (stderr)
899      xmlMemDisplay(stderr);
900 #endif
901 }
902 
903 #ifdef MEM_LIST
904 static FILE *xmlMemoryDumpFile = NULL;
905 #endif
906 
907 /**
908  * xmlMemShow:
909  * @fp:  a FILE descriptor used as the output file
910  * @nr:  number of entries to dump
911  *
912  * show a show display of the memory allocated, and dump
913  * the @nr last allocated areas which were not freed
914  */
915 
916 void
xmlMemShow(FILE * fp,int nr ATTRIBUTE_UNUSED)917 xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
918 {
919 #ifdef MEM_LIST
920     MEMHDR *p;
921 #endif
922 
923     if (fp != NULL)
924 	fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
925 		debugMemSize, debugMaxMemSize);
926 #ifdef MEM_LIST
927     xmlMutexLock(xmlMemMutex);
928     if (nr > 0) {
929 	fprintf(fp,"NUMBER   SIZE  TYPE   WHERE\n");
930 	p = memlist;
931 	while ((p) && nr > 0) {
932 	      fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
933 	    switch (p->mh_type) {
934 	       case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
935 	       case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
936 	       case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
937 	      case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
938 	      case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
939 		default:fprintf(fp,"   ???    in ");break;
940 	    }
941 	    if (p->mh_file != NULL)
942 	        fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
943 	    if (p->mh_tag != MEMTAG)
944 		fprintf(fp,"  INVALID");
945 	    xmlMemContentShow(fp, p);
946 	    fprintf(fp,"\n");
947 	    nr--;
948 	    p = p->mh_next;
949 	}
950     }
951     xmlMutexUnlock(xmlMemMutex);
952 #endif /* MEM_LIST */
953 }
954 
955 /**
956  * xmlMemoryDump:
957  *
958  * Dump in-extenso the memory blocks allocated to the file .memorylist
959  */
960 
961 void
xmlMemoryDump(void)962 xmlMemoryDump(void)
963 {
964 #ifdef MEM_LIST
965     FILE *dump;
966 
967     if (debugMaxMemSize == 0)
968 	return;
969     dump = fopen(".memdump", "w");
970     if (dump == NULL)
971 	xmlMemoryDumpFile = stderr;
972     else xmlMemoryDumpFile = dump;
973 
974     xmlMemDisplay(xmlMemoryDumpFile);
975 
976     if (dump != NULL) fclose(dump);
977 #endif /* MEM_LIST */
978 }
979 
980 
981 /****************************************************************
982  *								*
983  *		Initialization Routines				*
984  *								*
985  ****************************************************************/
986 
987 /**
988  * xmlInitMemory:
989  *
990  * Initialize the memory layer.
991  *
992  * Returns 0 on success
993  */
994 int
xmlInitMemory(void)995 xmlInitMemory(void)
996 {
997 #ifdef HAVE_STDLIB_H
998      char *breakpoint;
999 #endif
1000 #ifdef DEBUG_MEMORY
1001      xmlGenericError(xmlGenericErrorContext,
1002 	     "xmlInitMemory()\n");
1003 #endif
1004     /*
1005      This is really not good code (see Bug 130419).  Suggestions for
1006      improvement will be welcome!
1007     */
1008      if (xmlMemInitialized) return(-1);
1009      xmlMemInitialized = 1;
1010      xmlMemMutex = xmlNewMutex();
1011 
1012 #ifdef HAVE_STDLIB_H
1013      breakpoint = getenv("XML_MEM_BREAKPOINT");
1014      if (breakpoint != NULL) {
1015          sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
1016      }
1017 #endif
1018 #ifdef HAVE_STDLIB_H
1019      breakpoint = getenv("XML_MEM_TRACE");
1020      if (breakpoint != NULL) {
1021          sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
1022      }
1023 #endif
1024 
1025 #ifdef DEBUG_MEMORY
1026      xmlGenericError(xmlGenericErrorContext,
1027 	     "xmlInitMemory() Ok\n");
1028 #endif
1029      return(0);
1030 }
1031 
1032 /**
1033  * xmlCleanupMemory:
1034  *
1035  * Free up all the memory allocated by the library for its own
1036  * use. This should not be called by user level code.
1037  */
1038 void
xmlCleanupMemory(void)1039 xmlCleanupMemory(void) {
1040 #ifdef DEBUG_MEMORY
1041      xmlGenericError(xmlGenericErrorContext,
1042 	     "xmlCleanupMemory()\n");
1043 #endif
1044     if (xmlMemInitialized == 0)
1045         return;
1046 
1047     xmlFreeMutex(xmlMemMutex);
1048     xmlMemMutex = NULL;
1049     xmlMemInitialized = 0;
1050 #ifdef DEBUG_MEMORY
1051      xmlGenericError(xmlGenericErrorContext,
1052 	     "xmlCleanupMemory() Ok\n");
1053 #endif
1054 }
1055 
1056 /**
1057  * xmlMemSetup:
1058  * @freeFunc: the free() function to use
1059  * @mallocFunc: the malloc() function to use
1060  * @reallocFunc: the realloc() function to use
1061  * @strdupFunc: the strdup() function to use
1062  *
1063  * Override the default memory access functions with a new set
1064  * This has to be called before any other libxml routines !
1065  *
1066  * Should this be blocked if there was already some allocations
1067  * done ?
1068  *
1069  * Returns 0 on success
1070  */
1071 int
xmlMemSetup(xmlFreeFunc freeFunc,xmlMallocFunc mallocFunc,xmlReallocFunc reallocFunc,xmlStrdupFunc strdupFunc)1072 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1073             xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
1074 #ifdef DEBUG_MEMORY
1075      xmlGenericError(xmlGenericErrorContext,
1076 	     "xmlMemSetup()\n");
1077 #endif
1078     if (freeFunc == NULL)
1079 	return(-1);
1080     if (mallocFunc == NULL)
1081 	return(-1);
1082     if (reallocFunc == NULL)
1083 	return(-1);
1084     if (strdupFunc == NULL)
1085 	return(-1);
1086     xmlFree = freeFunc;
1087     xmlMalloc = mallocFunc;
1088     xmlMallocAtomic = mallocFunc;
1089     xmlRealloc = reallocFunc;
1090     xmlMemStrdup = strdupFunc;
1091 #ifdef DEBUG_MEMORY
1092      xmlGenericError(xmlGenericErrorContext,
1093 	     "xmlMemSetup() Ok\n");
1094 #endif
1095     return(0);
1096 }
1097 
1098 /**
1099  * xmlMemGet:
1100  * @freeFunc: place to save the free() function in use
1101  * @mallocFunc: place to save the malloc() function in use
1102  * @reallocFunc: place to save the realloc() function in use
1103  * @strdupFunc: place to save the strdup() function in use
1104  *
1105  * Provides the memory access functions set currently in use
1106  *
1107  * Returns 0 on success
1108  */
1109 int
xmlMemGet(xmlFreeFunc * freeFunc,xmlMallocFunc * mallocFunc,xmlReallocFunc * reallocFunc,xmlStrdupFunc * strdupFunc)1110 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1111 	  xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
1112     if (freeFunc != NULL) *freeFunc = xmlFree;
1113     if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1114     if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1115     if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1116     return(0);
1117 }
1118 
1119 /**
1120  * xmlGcMemSetup:
1121  * @freeFunc: the free() function to use
1122  * @mallocFunc: the malloc() function to use
1123  * @mallocAtomicFunc: the malloc() function to use for atomic allocations
1124  * @reallocFunc: the realloc() function to use
1125  * @strdupFunc: the strdup() function to use
1126  *
1127  * Override the default memory access functions with a new set
1128  * This has to be called before any other libxml routines !
1129  * The mallocAtomicFunc is specialized for atomic block
1130  * allocations (i.e. of areas  useful for garbage collected memory allocators
1131  *
1132  * Should this be blocked if there was already some allocations
1133  * done ?
1134  *
1135  * Returns 0 on success
1136  */
1137 int
xmlGcMemSetup(xmlFreeFunc freeFunc,xmlMallocFunc mallocFunc,xmlMallocFunc mallocAtomicFunc,xmlReallocFunc reallocFunc,xmlStrdupFunc strdupFunc)1138 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1139               xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
1140 	      xmlStrdupFunc strdupFunc) {
1141 #ifdef DEBUG_MEMORY
1142      xmlGenericError(xmlGenericErrorContext,
1143 	     "xmlGcMemSetup()\n");
1144 #endif
1145     if (freeFunc == NULL)
1146 	return(-1);
1147     if (mallocFunc == NULL)
1148 	return(-1);
1149     if (mallocAtomicFunc == NULL)
1150 	return(-1);
1151     if (reallocFunc == NULL)
1152 	return(-1);
1153     if (strdupFunc == NULL)
1154 	return(-1);
1155     xmlFree = freeFunc;
1156     xmlMalloc = mallocFunc;
1157     xmlMallocAtomic = mallocAtomicFunc;
1158     xmlRealloc = reallocFunc;
1159     xmlMemStrdup = strdupFunc;
1160 #ifdef DEBUG_MEMORY
1161      xmlGenericError(xmlGenericErrorContext,
1162 	     "xmlGcMemSetup() Ok\n");
1163 #endif
1164     return(0);
1165 }
1166 
1167 /**
1168  * xmlGcMemGet:
1169  * @freeFunc: place to save the free() function in use
1170  * @mallocFunc: place to save the malloc() function in use
1171  * @mallocAtomicFunc: place to save the atomic malloc() function in use
1172  * @reallocFunc: place to save the realloc() function in use
1173  * @strdupFunc: place to save the strdup() function in use
1174  *
1175  * Provides the memory access functions set currently in use
1176  * The mallocAtomicFunc is specialized for atomic block
1177  * allocations (i.e. of areas  useful for garbage collected memory allocators
1178  *
1179  * Returns 0 on success
1180  */
1181 int
xmlGcMemGet(xmlFreeFunc * freeFunc,xmlMallocFunc * mallocFunc,xmlMallocFunc * mallocAtomicFunc,xmlReallocFunc * reallocFunc,xmlStrdupFunc * strdupFunc)1182 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1183             xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
1184 	    xmlStrdupFunc *strdupFunc) {
1185     if (freeFunc != NULL) *freeFunc = xmlFree;
1186     if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1187     if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
1188     if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1189     if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1190     return(0);
1191 }
1192 
1193 #define bottom_xmlmemory
1194 #include "elfgcchack.h"
1195