Imported Upstream version 2.9.4
[platform/upstream/libxml2.git] / xmlmemory.c
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
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15
16 #ifdef HAVE_TIME_H
17 #include <time.h>
18 #endif
19
20 #ifdef HAVE_STDLIB_H
21 #include <stdlib.h>
22 #else
23 #ifdef HAVE_MALLOC_H
24 #include <malloc.h>
25 #endif
26 #endif
27
28 #ifdef HAVE_CTYPE_H
29 #include <ctype.h>
30 #endif
31
32 /* #define DEBUG_MEMORY */
33
34 /**
35  * MEM_LIST:
36  *
37  * keep track of all allocated blocks for error reporting
38  * Always build the memory list !
39  */
40 #ifdef DEBUG_MEMORY_LOCATION
41 #ifndef MEM_LIST
42 #define MEM_LIST /* keep a list of all the allocated memory blocks */
43 #endif
44 #endif
45
46 #include <libxml/globals.h>     /* must come before xmlmemory.h */
47 #include <libxml/xmlmemory.h>
48 #include <libxml/xmlerror.h>
49 #include <libxml/threads.h>
50
51 static int xmlMemInitialized = 0;
52 static unsigned long  debugMemSize = 0;
53 static unsigned long  debugMemBlocks = 0;
54 static unsigned long  debugMaxMemSize = 0;
55 static xmlMutexPtr xmlMemMutex = NULL;
56
57 void xmlMallocBreakpoint(void);
58
59 /************************************************************************
60  *                                                                      *
61  *              Macros, variables and associated types                  *
62  *                                                                      *
63  ************************************************************************/
64
65 #if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
66 #ifdef xmlMalloc
67 #undef xmlMalloc
68 #endif
69 #ifdef xmlRealloc
70 #undef xmlRealloc
71 #endif
72 #ifdef xmlMemStrdup
73 #undef xmlMemStrdup
74 #endif
75 #endif
76
77 /*
78  * Each of the blocks allocated begin with a header containing informations
79  */
80
81 #define MEMTAG 0x5aa5
82
83 #define MALLOC_TYPE 1
84 #define REALLOC_TYPE 2
85 #define STRDUP_TYPE 3
86 #define MALLOC_ATOMIC_TYPE 4
87 #define REALLOC_ATOMIC_TYPE 5
88
89 typedef struct memnod {
90     unsigned int   mh_tag;
91     unsigned int   mh_type;
92     unsigned long  mh_number;
93     size_t         mh_size;
94 #ifdef MEM_LIST
95    struct memnod *mh_next;
96    struct memnod *mh_prev;
97 #endif
98    const char    *mh_file;
99    unsigned int   mh_line;
100 }  MEMHDR;
101
102
103 #ifdef SUN4
104 #define ALIGN_SIZE  16
105 #else
106 #define ALIGN_SIZE  sizeof(double)
107 #endif
108 #define HDR_SIZE    sizeof(MEMHDR)
109 #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
110                       / ALIGN_SIZE ) * ALIGN_SIZE)
111
112 #define MAX_SIZE_T ((size_t)-1)
113
114 #define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
115 #define HDR_2_CLIENT(a)    ((void *) (((char *) (a)) + RESERVE_SIZE))
116
117
118 static unsigned int block=0;
119 static unsigned int xmlMemStopAtBlock = 0;
120 static void *xmlMemTraceBlockAt = NULL;
121 #ifdef MEM_LIST
122 static MEMHDR *memlist = NULL;
123 #endif
124
125 static void debugmem_tag_error(void *addr);
126 #ifdef MEM_LIST
127 static void  debugmem_list_add(MEMHDR *);
128 static void debugmem_list_delete(MEMHDR *);
129 #endif
130 #define Mem_Tag_Err(a) debugmem_tag_error(a);
131
132 #ifndef TEST_POINT
133 #define TEST_POINT
134 #endif
135
136 /**
137  * xmlMallocBreakpoint:
138  *
139  * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
140  * number reaches the specified value this function is called. One need to add a breakpoint
141  * to it to get the context in which the given block is allocated.
142  */
143
144 void
145 xmlMallocBreakpoint(void) {
146     xmlGenericError(xmlGenericErrorContext,
147             "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
148 }
149
150 /**
151  * xmlMallocLoc:
152  * @size:  an int specifying the size in byte to allocate.
153  * @file:  the file name or NULL
154  * @line:  the line number
155  *
156  * a malloc() equivalent, with logging of the allocation info.
157  *
158  * Returns a pointer to the allocated area or NULL in case of lack of memory.
159  */
160
161 void *
162 xmlMallocLoc(size_t size, const char * file, int line)
163 {
164     MEMHDR *p;
165     void *ret;
166
167     if (!xmlMemInitialized) xmlInitMemory();
168 #ifdef DEBUG_MEMORY
169     xmlGenericError(xmlGenericErrorContext,
170             "Malloc(%d)\n",size);
171 #endif
172
173     TEST_POINT
174
175     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
176
177     if (!p) {
178         xmlGenericError(xmlGenericErrorContext,
179                 "xmlMallocLoc : Out of free space\n");
180         xmlMemoryDump();
181         return(NULL);
182     }
183     p->mh_tag = MEMTAG;
184     p->mh_size = size;
185     p->mh_type = MALLOC_TYPE;
186     p->mh_file = file;
187     p->mh_line = line;
188     xmlMutexLock(xmlMemMutex);
189     p->mh_number = ++block;
190     debugMemSize += size;
191     debugMemBlocks++;
192     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
193 #ifdef MEM_LIST
194     debugmem_list_add(p);
195 #endif
196     xmlMutexUnlock(xmlMemMutex);
197
198 #ifdef DEBUG_MEMORY
199     xmlGenericError(xmlGenericErrorContext,
200             "Malloc(%d) Ok\n",size);
201 #endif
202
203     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
204
205     ret = HDR_2_CLIENT(p);
206
207     if (xmlMemTraceBlockAt == ret) {
208         xmlGenericError(xmlGenericErrorContext,
209                         "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
210                         (long unsigned)size);
211         xmlMallocBreakpoint();
212     }
213
214     TEST_POINT
215
216     return(ret);
217 }
218
219 /**
220  * xmlMallocAtomicLoc:
221  * @size:  an unsigned int specifying the size in byte to allocate.
222  * @file:  the file name or NULL
223  * @line:  the line number
224  *
225  * a malloc() equivalent, with logging of the allocation info.
226  *
227  * Returns a pointer to the allocated area or NULL in case of lack of memory.
228  */
229
230 void *
231 xmlMallocAtomicLoc(size_t size, const char * file, int line)
232 {
233     MEMHDR *p;
234     void *ret;
235
236     if (!xmlMemInitialized) xmlInitMemory();
237 #ifdef DEBUG_MEMORY
238     xmlGenericError(xmlGenericErrorContext,
239             "Malloc(%d)\n",size);
240 #endif
241
242     TEST_POINT
243
244     if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
245         xmlGenericError(xmlGenericErrorContext,
246                 "xmlMallocAtomicLoc : Unsigned overflow prevented\n");
247         xmlMemoryDump();
248         return(NULL);
249     }
250
251     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
252
253     if (!p) {
254         xmlGenericError(xmlGenericErrorContext,
255                 "xmlMallocAtomicLoc : Out of free space\n");
256         xmlMemoryDump();
257         return(NULL);
258     }
259     p->mh_tag = MEMTAG;
260     p->mh_size = size;
261     p->mh_type = MALLOC_ATOMIC_TYPE;
262     p->mh_file = file;
263     p->mh_line = line;
264     xmlMutexLock(xmlMemMutex);
265     p->mh_number = ++block;
266     debugMemSize += size;
267     debugMemBlocks++;
268     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
269 #ifdef MEM_LIST
270     debugmem_list_add(p);
271 #endif
272     xmlMutexUnlock(xmlMemMutex);
273
274 #ifdef DEBUG_MEMORY
275     xmlGenericError(xmlGenericErrorContext,
276             "Malloc(%d) Ok\n",size);
277 #endif
278
279     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
280
281     ret = HDR_2_CLIENT(p);
282
283     if (xmlMemTraceBlockAt == ret) {
284         xmlGenericError(xmlGenericErrorContext,
285                         "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
286                         (long unsigned)size);
287         xmlMallocBreakpoint();
288     }
289
290     TEST_POINT
291
292     return(ret);
293 }
294 /**
295  * xmlMemMalloc:
296  * @size:  an int specifying the size in byte to allocate.
297  *
298  * a malloc() equivalent, with logging of the allocation info.
299  *
300  * Returns a pointer to the allocated area or NULL in case of lack of memory.
301  */
302
303 void *
304 xmlMemMalloc(size_t size)
305 {
306     return(xmlMallocLoc(size, "none", 0));
307 }
308
309 /**
310  * xmlReallocLoc:
311  * @ptr:  the initial memory block pointer
312  * @size:  an int specifying the size in byte to allocate.
313  * @file:  the file name or NULL
314  * @line:  the line number
315  *
316  * a realloc() equivalent, with logging of the allocation info.
317  *
318  * Returns a pointer to the allocated area or NULL in case of lack of memory.
319  */
320
321 void *
322 xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
323 {
324     MEMHDR *p, *tmp;
325     unsigned long number;
326 #ifdef DEBUG_MEMORY
327     size_t oldsize;
328 #endif
329
330     if (ptr == NULL)
331         return(xmlMallocLoc(size, file, line));
332
333     if (!xmlMemInitialized) xmlInitMemory();
334     TEST_POINT
335
336     p = CLIENT_2_HDR(ptr);
337     number = p->mh_number;
338     if (xmlMemStopAtBlock == number) xmlMallocBreakpoint();
339     if (p->mh_tag != MEMTAG) {
340        Mem_Tag_Err(p);
341          goto error;
342     }
343     p->mh_tag = ~MEMTAG;
344     xmlMutexLock(xmlMemMutex);
345     debugMemSize -= p->mh_size;
346     debugMemBlocks--;
347 #ifdef DEBUG_MEMORY
348     oldsize = p->mh_size;
349 #endif
350 #ifdef MEM_LIST
351     debugmem_list_delete(p);
352 #endif
353     xmlMutexUnlock(xmlMemMutex);
354
355     tmp = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
356     if (!tmp) {
357          free(p);
358          goto error;
359     }
360     p = tmp;
361     if (xmlMemTraceBlockAt == ptr) {
362         xmlGenericError(xmlGenericErrorContext,
363                         "%p : Realloced(%lu -> %lu) Ok\n",
364                         xmlMemTraceBlockAt, (long unsigned)p->mh_size,
365                         (long unsigned)size);
366         xmlMallocBreakpoint();
367     }
368     p->mh_tag = MEMTAG;
369     p->mh_number = number;
370     p->mh_type = REALLOC_TYPE;
371     p->mh_size = size;
372     p->mh_file = file;
373     p->mh_line = line;
374     xmlMutexLock(xmlMemMutex);
375     debugMemSize += size;
376     debugMemBlocks++;
377     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
378 #ifdef MEM_LIST
379     debugmem_list_add(p);
380 #endif
381     xmlMutexUnlock(xmlMemMutex);
382
383     TEST_POINT
384
385 #ifdef DEBUG_MEMORY
386     xmlGenericError(xmlGenericErrorContext,
387             "Realloced(%d to %d) Ok\n", oldsize, size);
388 #endif
389     return(HDR_2_CLIENT(p));
390
391 error:
392     return(NULL);
393 }
394
395 /**
396  * xmlMemRealloc:
397  * @ptr:  the initial memory block pointer
398  * @size:  an int specifying the size in byte to allocate.
399  *
400  * a realloc() equivalent, with logging of the allocation info.
401  *
402  * Returns a pointer to the allocated area or NULL in case of lack of memory.
403  */
404
405 void *
406 xmlMemRealloc(void *ptr,size_t size) {
407     return(xmlReallocLoc(ptr, size, "none", 0));
408 }
409
410 /**
411  * xmlMemFree:
412  * @ptr:  the memory block pointer
413  *
414  * a free() equivalent, with error checking.
415  */
416 void
417 xmlMemFree(void *ptr)
418 {
419     MEMHDR *p;
420     char *target;
421 #ifdef DEBUG_MEMORY
422     size_t size;
423 #endif
424
425     if (ptr == NULL)
426         return;
427
428     if (ptr == (void *) -1) {
429         xmlGenericError(xmlGenericErrorContext,
430             "trying to free pointer from freed area\n");
431         goto error;
432     }
433
434     if (xmlMemTraceBlockAt == ptr) {
435         xmlGenericError(xmlGenericErrorContext,
436                         "%p : Freed()\n", xmlMemTraceBlockAt);
437         xmlMallocBreakpoint();
438     }
439
440     TEST_POINT
441
442     target = (char *) ptr;
443
444     p = CLIENT_2_HDR(ptr);
445     if (p->mh_tag != MEMTAG) {
446         Mem_Tag_Err(p);
447         goto error;
448     }
449     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
450     p->mh_tag = ~MEMTAG;
451     memset(target, -1, p->mh_size);
452     xmlMutexLock(xmlMemMutex);
453     debugMemSize -= p->mh_size;
454     debugMemBlocks--;
455 #ifdef DEBUG_MEMORY
456     size = p->mh_size;
457 #endif
458 #ifdef MEM_LIST
459     debugmem_list_delete(p);
460 #endif
461     xmlMutexUnlock(xmlMemMutex);
462
463     free(p);
464
465     TEST_POINT
466
467 #ifdef DEBUG_MEMORY
468     xmlGenericError(xmlGenericErrorContext,
469             "Freed(%d) Ok\n", size);
470 #endif
471
472     return;
473
474 error:
475     xmlGenericError(xmlGenericErrorContext,
476             "xmlMemFree(%lX) error\n", (unsigned long) ptr);
477     xmlMallocBreakpoint();
478     return;
479 }
480
481 /**
482  * xmlMemStrdupLoc:
483  * @str:  the initial string pointer
484  * @file:  the file name or NULL
485  * @line:  the line number
486  *
487  * a strdup() equivalent, with logging of the allocation info.
488  *
489  * Returns a pointer to the new string or NULL if allocation error occurred.
490  */
491
492 char *
493 xmlMemStrdupLoc(const char *str, const char *file, int line)
494 {
495     char *s;
496     size_t size = strlen(str) + 1;
497     MEMHDR *p;
498
499     if (!xmlMemInitialized) xmlInitMemory();
500     TEST_POINT
501
502     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
503     if (!p) {
504       goto error;
505     }
506     p->mh_tag = MEMTAG;
507     p->mh_size = size;
508     p->mh_type = STRDUP_TYPE;
509     p->mh_file = file;
510     p->mh_line = line;
511     xmlMutexLock(xmlMemMutex);
512     p->mh_number = ++block;
513     debugMemSize += size;
514     debugMemBlocks++;
515     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
516 #ifdef MEM_LIST
517     debugmem_list_add(p);
518 #endif
519     xmlMutexUnlock(xmlMemMutex);
520
521     s = (char *) HDR_2_CLIENT(p);
522
523     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
524
525     strcpy(s,str);
526
527     TEST_POINT
528
529     if (xmlMemTraceBlockAt == s) {
530         xmlGenericError(xmlGenericErrorContext,
531                         "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
532         xmlMallocBreakpoint();
533     }
534
535     return(s);
536
537 error:
538     return(NULL);
539 }
540
541 /**
542  * xmlMemoryStrdup:
543  * @str:  the initial string pointer
544  *
545  * a strdup() equivalent, with logging of the allocation info.
546  *
547  * Returns a pointer to the new string or NULL if allocation error occurred.
548  */
549
550 char *
551 xmlMemoryStrdup(const char *str) {
552     return(xmlMemStrdupLoc(str, "none", 0));
553 }
554
555 /**
556  * xmlMemUsed:
557  *
558  * Provides the amount of memory currently allocated
559  *
560  * Returns an int representing the amount of memory allocated.
561  */
562
563 int
564 xmlMemUsed(void) {
565     int res;
566
567     xmlMutexLock(xmlMemMutex);
568     res = debugMemSize;
569     xmlMutexUnlock(xmlMemMutex);
570     return(res);
571 }
572
573 /**
574  * xmlMemBlocks:
575  *
576  * Provides the number of memory areas currently allocated
577  *
578  * Returns an int representing the number of blocks
579  */
580
581 int
582 xmlMemBlocks(void) {
583     int res;
584
585     xmlMutexLock(xmlMemMutex);
586     res = debugMemBlocks;
587     xmlMutexUnlock(xmlMemMutex);
588     return(res);
589 }
590
591 #ifdef MEM_LIST
592 /**
593  * xmlMemContentShow:
594  * @fp:  a FILE descriptor used as the output file
595  * @p:  a memory block header
596  *
597  * tries to show some content from the memory block
598  */
599
600 static void
601 xmlMemContentShow(FILE *fp, MEMHDR *p)
602 {
603     int i,j,k,len;
604     const char *buf;
605
606     if (p == NULL) {
607         fprintf(fp, " NULL");
608         return;
609     }
610     len = p->mh_size;
611     buf = (const char *) HDR_2_CLIENT(p);
612
613     for (i = 0;i < len;i++) {
614         if (buf[i] == 0) break;
615         if (!isprint((unsigned char) buf[i])) break;
616     }
617     if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
618         if (len >= 4) {
619             MEMHDR *q;
620             void *cur;
621
622             for (j = 0;(j < len -3) && (j < 40);j += 4) {
623                 cur = *((void **) &buf[j]);
624                 q = CLIENT_2_HDR(cur);
625                 p = memlist;
626                 k = 0;
627                 while (p != NULL) {
628                     if (p == q) break;
629                     p = p->mh_next;
630                     if (k++ > 100) break;
631                 }
632                 if ((p != NULL) && (p == q)) {
633                     fprintf(fp, " pointer to #%lu at index %d",
634                             p->mh_number, j);
635                     return;
636                 }
637             }
638         }
639     } else if ((i == 0) && (buf[i] == 0)) {
640         fprintf(fp," null");
641     } else {
642         if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
643         else {
644             fprintf(fp," [");
645             for (j = 0;j < i;j++)
646                 fprintf(fp,"%c", buf[j]);
647             fprintf(fp,"]");
648         }
649     }
650 }
651 #endif
652
653 /**
654  * xmlMemDisplayLast:
655  * @fp:  a FILE descriptor used as the output file, if NULL, the result is
656  *       written to the file .memorylist
657  * @nbBytes: the amount of memory to dump
658  *
659  * the last nbBytes of memory allocated and not freed, useful for dumping
660  * the memory left allocated between two places at runtime.
661  */
662
663 void
664 xmlMemDisplayLast(FILE *fp, long nbBytes)
665 {
666 #ifdef MEM_LIST
667     MEMHDR *p;
668     unsigned idx;
669     int     nb = 0;
670 #endif
671     FILE *old_fp = fp;
672
673     if (nbBytes <= 0)
674         return;
675
676     if (fp == NULL) {
677         fp = fopen(".memorylist", "w");
678         if (fp == NULL)
679             return;
680     }
681
682 #ifdef MEM_LIST
683     fprintf(fp,"   Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
684             nbBytes, debugMemSize, debugMaxMemSize);
685     fprintf(fp,"BLOCK  NUMBER   SIZE  TYPE\n");
686     idx = 0;
687     xmlMutexLock(xmlMemMutex);
688     p = memlist;
689     while ((p) && (nbBytes > 0)) {
690           fprintf(fp,"%-5u  %6lu %6lu ",idx++,p->mh_number,
691                   (unsigned long)p->mh_size);
692         switch (p->mh_type) {
693            case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
694            case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
695            case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
696            case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
697            case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
698            default:
699                 fprintf(fp,"Unknown memory block, may be corrupted");
700                 xmlMutexUnlock(xmlMemMutex);
701                 if (old_fp == NULL)
702                     fclose(fp);
703                 return;
704         }
705         if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
706         if (p->mh_tag != MEMTAG)
707               fprintf(fp,"  INVALID");
708         nb++;
709         if (nb < 100)
710             xmlMemContentShow(fp, p);
711         else
712             fprintf(fp," skip");
713
714         fprintf(fp,"\n");
715         nbBytes -= (unsigned long)p->mh_size;
716         p = p->mh_next;
717     }
718     xmlMutexUnlock(xmlMemMutex);
719 #else
720     fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
721 #endif
722     if (old_fp == NULL)
723         fclose(fp);
724 }
725
726 /**
727  * xmlMemDisplay:
728  * @fp:  a FILE descriptor used as the output file, if NULL, the result is
729  *       written to the file .memorylist
730  *
731  * show in-extenso the memory blocks allocated
732  */
733
734 void
735 xmlMemDisplay(FILE *fp)
736 {
737 #ifdef MEM_LIST
738     MEMHDR *p;
739     unsigned idx;
740     int     nb = 0;
741 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
742     time_t currentTime;
743     char buf[500];
744     struct tm * tstruct;
745 #endif
746 #endif
747     FILE *old_fp = fp;
748
749     if (fp == NULL) {
750         fp = fopen(".memorylist", "w");
751         if (fp == NULL)
752             return;
753     }
754
755 #ifdef MEM_LIST
756 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
757     currentTime = time(NULL);
758     tstruct = localtime(&currentTime);
759     strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
760     fprintf(fp,"      %s\n\n", buf);
761 #endif
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
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
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
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
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
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  * Initialize the memory layer.
939  *
940  * Returns 0 on success
941  */
942 int
943 xmlInitMemory(void)
944 {
945 #ifdef HAVE_STDLIB_H
946      char *breakpoint;
947 #endif
948 #ifdef DEBUG_MEMORY
949      xmlGenericError(xmlGenericErrorContext,
950              "xmlInitMemory()\n");
951 #endif
952     /*
953      This is really not good code (see Bug 130419).  Suggestions for
954      improvement will be welcome!
955     */
956      if (xmlMemInitialized) return(-1);
957      xmlMemInitialized = 1;
958      xmlMemMutex = xmlNewMutex();
959
960 #ifdef HAVE_STDLIB_H
961      breakpoint = getenv("XML_MEM_BREAKPOINT");
962      if (breakpoint != NULL) {
963          sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
964      }
965 #endif
966 #ifdef HAVE_STDLIB_H
967      breakpoint = getenv("XML_MEM_TRACE");
968      if (breakpoint != NULL) {
969          sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
970      }
971 #endif
972
973 #ifdef DEBUG_MEMORY
974      xmlGenericError(xmlGenericErrorContext,
975              "xmlInitMemory() Ok\n");
976 #endif
977      return(0);
978 }
979
980 /**
981  * xmlCleanupMemory:
982  *
983  * Free up all the memory allocated by the library for its own
984  * use. This should not be called by user level code.
985  */
986 void
987 xmlCleanupMemory(void) {
988 #ifdef DEBUG_MEMORY
989      xmlGenericError(xmlGenericErrorContext,
990              "xmlCleanupMemory()\n");
991 #endif
992     if (xmlMemInitialized == 0)
993         return;
994
995     xmlFreeMutex(xmlMemMutex);
996     xmlMemMutex = NULL;
997     xmlMemInitialized = 0;
998 #ifdef DEBUG_MEMORY
999      xmlGenericError(xmlGenericErrorContext,
1000              "xmlCleanupMemory() Ok\n");
1001 #endif
1002 }
1003
1004 /**
1005  * xmlMemSetup:
1006  * @freeFunc: the free() function to use
1007  * @mallocFunc: the malloc() function to use
1008  * @reallocFunc: the realloc() function to use
1009  * @strdupFunc: the strdup() function to use
1010  *
1011  * Override the default memory access functions with a new set
1012  * This has to be called before any other libxml routines !
1013  *
1014  * Should this be blocked if there was already some allocations
1015  * done ?
1016  *
1017  * Returns 0 on success
1018  */
1019 int
1020 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1021             xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
1022 #ifdef DEBUG_MEMORY
1023      xmlGenericError(xmlGenericErrorContext,
1024              "xmlMemSetup()\n");
1025 #endif
1026     if (freeFunc == NULL)
1027         return(-1);
1028     if (mallocFunc == NULL)
1029         return(-1);
1030     if (reallocFunc == NULL)
1031         return(-1);
1032     if (strdupFunc == NULL)
1033         return(-1);
1034     xmlFree = freeFunc;
1035     xmlMalloc = mallocFunc;
1036     xmlMallocAtomic = mallocFunc;
1037     xmlRealloc = reallocFunc;
1038     xmlMemStrdup = strdupFunc;
1039 #ifdef DEBUG_MEMORY
1040      xmlGenericError(xmlGenericErrorContext,
1041              "xmlMemSetup() Ok\n");
1042 #endif
1043     return(0);
1044 }
1045
1046 /**
1047  * xmlMemGet:
1048  * @freeFunc: place to save the free() function in use
1049  * @mallocFunc: place to save the malloc() function in use
1050  * @reallocFunc: place to save the realloc() function in use
1051  * @strdupFunc: place to save the strdup() function in use
1052  *
1053  * Provides the memory access functions set currently in use
1054  *
1055  * Returns 0 on success
1056  */
1057 int
1058 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1059           xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
1060     if (freeFunc != NULL) *freeFunc = xmlFree;
1061     if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1062     if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1063     if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1064     return(0);
1065 }
1066
1067 /**
1068  * xmlGcMemSetup:
1069  * @freeFunc: the free() function to use
1070  * @mallocFunc: the malloc() function to use
1071  * @mallocAtomicFunc: the malloc() function to use for atomic allocations
1072  * @reallocFunc: the realloc() function to use
1073  * @strdupFunc: the strdup() function to use
1074  *
1075  * Override the default memory access functions with a new set
1076  * This has to be called before any other libxml routines !
1077  * The mallocAtomicFunc is specialized for atomic block
1078  * allocations (i.e. of areas  useful for garbage collected memory allocators
1079  *
1080  * Should this be blocked if there was already some allocations
1081  * done ?
1082  *
1083  * Returns 0 on success
1084  */
1085 int
1086 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1087               xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
1088               xmlStrdupFunc strdupFunc) {
1089 #ifdef DEBUG_MEMORY
1090      xmlGenericError(xmlGenericErrorContext,
1091              "xmlGcMemSetup()\n");
1092 #endif
1093     if (freeFunc == NULL)
1094         return(-1);
1095     if (mallocFunc == NULL)
1096         return(-1);
1097     if (mallocAtomicFunc == NULL)
1098         return(-1);
1099     if (reallocFunc == NULL)
1100         return(-1);
1101     if (strdupFunc == NULL)
1102         return(-1);
1103     xmlFree = freeFunc;
1104     xmlMalloc = mallocFunc;
1105     xmlMallocAtomic = mallocAtomicFunc;
1106     xmlRealloc = reallocFunc;
1107     xmlMemStrdup = strdupFunc;
1108 #ifdef DEBUG_MEMORY
1109      xmlGenericError(xmlGenericErrorContext,
1110              "xmlGcMemSetup() Ok\n");
1111 #endif
1112     return(0);
1113 }
1114
1115 /**
1116  * xmlGcMemGet:
1117  * @freeFunc: place to save the free() function in use
1118  * @mallocFunc: place to save the malloc() function in use
1119  * @mallocAtomicFunc: place to save the atomic malloc() function in use
1120  * @reallocFunc: place to save the realloc() function in use
1121  * @strdupFunc: place to save the strdup() function in use
1122  *
1123  * Provides the memory access functions set currently in use
1124  * The mallocAtomicFunc is specialized for atomic block
1125  * allocations (i.e. of areas  useful for garbage collected memory allocators
1126  *
1127  * Returns 0 on success
1128  */
1129 int
1130 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1131             xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
1132             xmlStrdupFunc *strdupFunc) {
1133     if (freeFunc != NULL) *freeFunc = xmlFree;
1134     if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1135     if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
1136     if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1137     if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1138     return(0);
1139 }
1140
1141 #define bottom_xmlmemory
1142 #include "elfgcchack.h"