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