2 * xmlmemory.c: libxml memory allocator wrapper.
15 /* #define DEBUG_MEMORY */
20 * keep track of all allocated blocks for error reporting
21 * Always build the memory list !
23 #ifdef DEBUG_MEMORY_LOCATION
25 #define MEM_LIST /* keep a list of all the allocated memory blocks */
29 #include <libxml/globals.h> /* must come before xmlmemory.h */
30 #include <libxml/xmlmemory.h>
31 #include <libxml/xmlerror.h>
32 #include <libxml/threads.h>
34 #include "private/memory.h"
35 #include "private/threads.h"
37 static unsigned long debugMemSize
= 0;
38 static unsigned long debugMemBlocks
= 0;
39 static unsigned long debugMaxMemSize
= 0;
40 static xmlMutex xmlMemMutex
;
42 void xmlMallocBreakpoint(void);
44 /************************************************************************
46 * Macros, variables and associated types *
48 ************************************************************************/
50 #if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
63 * Each of the blocks allocated begin with a header containing information
66 #define MEMTAG 0x5aa5U
69 #define REALLOC_TYPE 2
71 #define MALLOC_ATOMIC_TYPE 4
72 #define REALLOC_ATOMIC_TYPE 5
74 typedef struct memnod
{
77 unsigned long mh_number
;
80 struct memnod
*mh_next
;
81 struct memnod
*mh_prev
;
91 #define ALIGN_SIZE sizeof(double)
93 #define HDR_SIZE sizeof(MEMHDR)
94 #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
95 / ALIGN_SIZE ) * ALIGN_SIZE)
97 #define MAX_SIZE_T ((size_t)-1)
99 #define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE))
100 #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
103 static unsigned int block
=0;
104 static unsigned int xmlMemStopAtBlock
= 0;
105 static void *xmlMemTraceBlockAt
= NULL
;
107 static MEMHDR
*memlist
= NULL
;
110 static void debugmem_tag_error(void *addr
);
112 static void debugmem_list_add(MEMHDR
*);
113 static void debugmem_list_delete(MEMHDR
*);
115 #define Mem_Tag_Err(a) debugmem_tag_error(a);
122 * xmlMallocBreakpoint:
124 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
125 * number reaches the specified value this function is called. One need to add a breakpoint
126 * to it to get the context in which the given block is allocated.
130 xmlMallocBreakpoint(void) {
131 xmlGenericError(xmlGenericErrorContext
,
132 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock
);
137 * @size: an int specifying the size in byte to allocate.
138 * @file: the file name or NULL
139 * @line: the line number
141 * a malloc() equivalent, with logging of the allocation info.
143 * Returns a pointer to the allocated area or NULL in case of lack of memory.
147 xmlMallocLoc(size_t size
, const char * file
, int line
)
154 xmlGenericError(xmlGenericErrorContext
,
155 "Malloc(%d)\n",size
);
160 if (size
> (MAX_SIZE_T
- RESERVE_SIZE
)) {
161 xmlGenericError(xmlGenericErrorContext
,
162 "xmlMallocLoc : Unsigned overflow\n");
167 p
= (MEMHDR
*) malloc(RESERVE_SIZE
+size
);
170 xmlGenericError(xmlGenericErrorContext
,
171 "xmlMallocLoc : Out of free space\n");
177 p
->mh_type
= MALLOC_TYPE
;
180 xmlMutexLock(&xmlMemMutex
);
181 p
->mh_number
= ++block
;
182 debugMemSize
+= size
;
184 if (debugMemSize
> debugMaxMemSize
) debugMaxMemSize
= debugMemSize
;
186 debugmem_list_add(p
);
188 xmlMutexUnlock(&xmlMemMutex
);
191 xmlGenericError(xmlGenericErrorContext
,
192 "Malloc(%d) Ok\n",size
);
195 if (xmlMemStopAtBlock
== p
->mh_number
) xmlMallocBreakpoint();
197 ret
= HDR_2_CLIENT(p
);
199 if (xmlMemTraceBlockAt
== ret
) {
200 xmlGenericError(xmlGenericErrorContext
,
201 "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt
,
202 (long unsigned)size
);
203 xmlMallocBreakpoint();
212 * xmlMallocAtomicLoc:
213 * @size: an unsigned int specifying the size in byte to allocate.
214 * @file: the file name or NULL
215 * @line: the line number
217 * a malloc() equivalent, with logging of the allocation info.
219 * Returns a pointer to the allocated area or NULL in case of lack of memory.
223 xmlMallocAtomicLoc(size_t size
, const char * file
, int line
)
230 xmlGenericError(xmlGenericErrorContext
,
231 "Malloc(%d)\n",size
);
236 if (size
> (MAX_SIZE_T
- RESERVE_SIZE
)) {
237 xmlGenericError(xmlGenericErrorContext
,
238 "xmlMallocAtomicLoc : Unsigned overflow\n");
243 p
= (MEMHDR
*) malloc(RESERVE_SIZE
+size
);
246 xmlGenericError(xmlGenericErrorContext
,
247 "xmlMallocAtomicLoc : Out of free space\n");
253 p
->mh_type
= MALLOC_ATOMIC_TYPE
;
256 xmlMutexLock(&xmlMemMutex
);
257 p
->mh_number
= ++block
;
258 debugMemSize
+= size
;
260 if (debugMemSize
> debugMaxMemSize
) debugMaxMemSize
= debugMemSize
;
262 debugmem_list_add(p
);
264 xmlMutexUnlock(&xmlMemMutex
);
267 xmlGenericError(xmlGenericErrorContext
,
268 "Malloc(%d) Ok\n",size
);
271 if (xmlMemStopAtBlock
== p
->mh_number
) xmlMallocBreakpoint();
273 ret
= HDR_2_CLIENT(p
);
275 if (xmlMemTraceBlockAt
== ret
) {
276 xmlGenericError(xmlGenericErrorContext
,
277 "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt
,
278 (long unsigned)size
);
279 xmlMallocBreakpoint();
288 * @size: an int specifying the size in byte to allocate.
290 * a malloc() equivalent, with logging of the allocation info.
292 * Returns a pointer to the allocated area or NULL in case of lack of memory.
296 xmlMemMalloc(size_t size
)
298 return(xmlMallocLoc(size
, "none", 0));
303 * @ptr: the initial memory block pointer
304 * @size: an int specifying the size in byte to allocate.
305 * @file: the file name or NULL
306 * @line: the line number
308 * a realloc() equivalent, with logging of the allocation info.
310 * Returns a pointer to the allocated area or NULL in case of lack of memory.
314 xmlReallocLoc(void *ptr
,size_t size
, const char * file
, int line
)
317 unsigned long number
;
323 return(xmlMallocLoc(size
, file
, line
));
328 p
= CLIENT_2_HDR(ptr
);
329 number
= p
->mh_number
;
330 if (xmlMemStopAtBlock
== number
) xmlMallocBreakpoint();
331 if (p
->mh_tag
!= MEMTAG
) {
336 xmlMutexLock(&xmlMemMutex
);
337 debugMemSize
-= p
->mh_size
;
340 oldsize
= p
->mh_size
;
343 debugmem_list_delete(p
);
345 xmlMutexUnlock(&xmlMemMutex
);
347 if (size
> (MAX_SIZE_T
- RESERVE_SIZE
)) {
348 xmlGenericError(xmlGenericErrorContext
,
349 "xmlReallocLoc : Unsigned overflow\n");
354 tmp
= (MEMHDR
*) realloc(p
,RESERVE_SIZE
+size
);
360 if (xmlMemTraceBlockAt
== ptr
) {
361 xmlGenericError(xmlGenericErrorContext
,
362 "%p : Realloced(%lu -> %lu) Ok\n",
363 xmlMemTraceBlockAt
, (long unsigned)p
->mh_size
,
364 (long unsigned)size
);
365 xmlMallocBreakpoint();
368 p
->mh_number
= number
;
369 p
->mh_type
= REALLOC_TYPE
;
373 xmlMutexLock(&xmlMemMutex
);
374 debugMemSize
+= size
;
376 if (debugMemSize
> debugMaxMemSize
) debugMaxMemSize
= debugMemSize
;
378 debugmem_list_add(p
);
380 xmlMutexUnlock(&xmlMemMutex
);
385 xmlGenericError(xmlGenericErrorContext
,
386 "Realloced(%d to %d) Ok\n", oldsize
, size
);
388 return(HDR_2_CLIENT(p
));
396 * @ptr: the initial memory block pointer
397 * @size: an int specifying the size in byte to allocate.
399 * a realloc() equivalent, with logging of the allocation info.
401 * Returns a pointer to the allocated area or NULL in case of lack of memory.
405 xmlMemRealloc(void *ptr
,size_t size
) {
406 return(xmlReallocLoc(ptr
, size
, "none", 0));
411 * @ptr: the memory block pointer
413 * a free() equivalent, with error checking.
416 xmlMemFree(void *ptr
)
427 if (ptr
== (void *) -1) {
428 xmlGenericError(xmlGenericErrorContext
,
429 "trying to free pointer from freed area\n");
433 if (xmlMemTraceBlockAt
== ptr
) {
434 xmlGenericError(xmlGenericErrorContext
,
435 "%p : Freed()\n", xmlMemTraceBlockAt
);
436 xmlMallocBreakpoint();
441 target
= (char *) ptr
;
443 p
= CLIENT_2_HDR(ptr
);
444 if (p
->mh_tag
!= MEMTAG
) {
448 if (xmlMemStopAtBlock
== p
->mh_number
) xmlMallocBreakpoint();
450 memset(target
, -1, p
->mh_size
);
451 xmlMutexLock(&xmlMemMutex
);
452 debugMemSize
-= p
->mh_size
;
458 debugmem_list_delete(p
);
460 xmlMutexUnlock(&xmlMemMutex
);
467 xmlGenericError(xmlGenericErrorContext
,
468 "Freed(%d) Ok\n", size
);
474 xmlGenericError(xmlGenericErrorContext
,
475 "xmlMemFree(%p) error\n", ptr
);
476 xmlMallocBreakpoint();
482 * @str: the initial string pointer
483 * @file: the file name or NULL
484 * @line: the line number
486 * a strdup() equivalent, with logging of the allocation info.
488 * Returns a pointer to the new string or NULL if allocation error occurred.
492 xmlMemStrdupLoc(const char *str
, const char *file
, int line
)
495 size_t size
= strlen(str
) + 1;
501 if (size
> (MAX_SIZE_T
- RESERVE_SIZE
)) {
502 xmlGenericError(xmlGenericErrorContext
,
503 "xmlMemStrdupLoc : Unsigned overflow\n");
508 p
= (MEMHDR
*) malloc(RESERVE_SIZE
+size
);
514 p
->mh_type
= STRDUP_TYPE
;
517 xmlMutexLock(&xmlMemMutex
);
518 p
->mh_number
= ++block
;
519 debugMemSize
+= size
;
521 if (debugMemSize
> debugMaxMemSize
) debugMaxMemSize
= debugMemSize
;
523 debugmem_list_add(p
);
525 xmlMutexUnlock(&xmlMemMutex
);
527 s
= (char *) HDR_2_CLIENT(p
);
529 if (xmlMemStopAtBlock
== p
->mh_number
) xmlMallocBreakpoint();
535 if (xmlMemTraceBlockAt
== s
) {
536 xmlGenericError(xmlGenericErrorContext
,
537 "%p : Strdup() Ok\n", xmlMemTraceBlockAt
);
538 xmlMallocBreakpoint();
549 * @str: the initial string pointer
551 * a strdup() equivalent, with logging of the allocation info.
553 * Returns a pointer to the new string or NULL if allocation error occurred.
557 xmlMemoryStrdup(const char *str
) {
558 return(xmlMemStrdupLoc(str
, "none", 0));
563 * @ptr: pointer to the memory allocation
565 * Returns the size of a memory allocation.
569 xmlMemSize(void *ptr
) {
575 p
= CLIENT_2_HDR(ptr
);
576 if (p
->mh_tag
!= MEMTAG
)
585 * Provides the amount of memory currently allocated
587 * Returns an int representing the amount of memory allocated.
592 return(debugMemSize
);
598 * Provides the number of memory areas currently allocated
600 * Returns an int representing the number of blocks
607 xmlMutexLock(&xmlMemMutex
);
608 res
= debugMemBlocks
;
609 xmlMutexUnlock(&xmlMemMutex
);
615 * @fp: a FILE descriptor used as the output file, if NULL, the result is
616 * written to the file .memorylist
617 * @nbBytes: the amount of memory to dump
619 * the last nbBytes of memory allocated and not freed, useful for dumping
620 * the memory left allocated between two places at runtime.
624 xmlMemDisplayLast(FILE *fp
, long nbBytes
)
637 fp
= fopen(".memorylist", "w");
643 fprintf(fp
," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
644 nbBytes
, debugMemSize
, debugMaxMemSize
);
645 fprintf(fp
,"BLOCK NUMBER SIZE TYPE\n");
647 xmlMutexLock(&xmlMemMutex
);
649 while ((p
) && (nbBytes
> 0)) {
650 fprintf(fp
,"%-5u %6lu %6lu ",idx
++,p
->mh_number
,
651 (unsigned long)p
->mh_size
);
652 switch (p
->mh_type
) {
653 case STRDUP_TYPE
:fprintf(fp
,"strdup() in ");break;
654 case MALLOC_TYPE
:fprintf(fp
,"malloc() in ");break;
655 case REALLOC_TYPE
:fprintf(fp
,"realloc() in ");break;
656 case MALLOC_ATOMIC_TYPE
:fprintf(fp
,"atomicmalloc() in ");break;
657 case REALLOC_ATOMIC_TYPE
:fprintf(fp
,"atomicrealloc() in ");break;
659 fprintf(fp
,"Unknown memory block, may be corrupted");
660 xmlMutexUnlock(&xmlMemMutex
);
665 if (p
->mh_file
!= NULL
) fprintf(fp
,"%s(%u)", p
->mh_file
, p
->mh_line
);
666 if (p
->mh_tag
!= MEMTAG
)
667 fprintf(fp
," INVALID");
671 nbBytes
-= (unsigned long)p
->mh_size
;
674 xmlMutexUnlock(&xmlMemMutex
);
676 fprintf(fp
,"Memory list not compiled (MEM_LIST not defined !)\n");
684 * @fp: a FILE descriptor used as the output file, if NULL, the result is
685 * written to the file .memorylist
687 * show in-extenso the memory blocks allocated
691 xmlMemDisplay(FILE *fp
)
704 fp
= fopen(".memorylist", "w");
710 currentTime
= time(NULL
);
711 tstruct
= localtime(¤tTime
);
712 strftime(buf
, sizeof(buf
) - 1, "%I:%M:%S %p", tstruct
);
713 fprintf(fp
," %s\n\n", buf
);
716 fprintf(fp
," MEMORY ALLOCATED : %lu, MAX was %lu\n",
717 debugMemSize
, debugMaxMemSize
);
718 fprintf(fp
,"BLOCK NUMBER SIZE TYPE\n");
720 xmlMutexLock(&xmlMemMutex
);
723 fprintf(fp
,"%-5u %6lu %6lu ",idx
++,p
->mh_number
,
724 (unsigned long)p
->mh_size
);
725 switch (p
->mh_type
) {
726 case STRDUP_TYPE
:fprintf(fp
,"strdup() in ");break;
727 case MALLOC_TYPE
:fprintf(fp
,"malloc() in ");break;
728 case REALLOC_TYPE
:fprintf(fp
,"realloc() in ");break;
729 case MALLOC_ATOMIC_TYPE
:fprintf(fp
,"atomicmalloc() in ");break;
730 case REALLOC_ATOMIC_TYPE
:fprintf(fp
,"atomicrealloc() in ");break;
732 fprintf(fp
,"Unknown memory block, may be corrupted");
733 xmlMutexUnlock(&xmlMemMutex
);
738 if (p
->mh_file
!= NULL
) fprintf(fp
,"%s(%u)", p
->mh_file
, p
->mh_line
);
739 if (p
->mh_tag
!= MEMTAG
)
740 fprintf(fp
," INVALID");
746 xmlMutexUnlock(&xmlMemMutex
);
748 fprintf(fp
,"Memory list not compiled (MEM_LIST not defined !)\n");
756 static void debugmem_list_add(MEMHDR
*p
)
758 p
->mh_next
= memlist
;
760 if (memlist
) memlist
->mh_prev
= p
;
762 #ifdef MEM_LIST_DEBUG
768 static void debugmem_list_delete(MEMHDR
*p
)
771 p
->mh_next
->mh_prev
= p
->mh_prev
;
773 p
->mh_prev
->mh_next
= p
->mh_next
;
774 else memlist
= p
->mh_next
;
775 #ifdef MEM_LIST_DEBUG
784 * debugmem_tag_error:
786 * internal error function.
789 static void debugmem_tag_error(void *p
)
791 xmlGenericError(xmlGenericErrorContext
,
792 "Memory tag error occurs :%p \n\t bye\n", p
);
795 xmlMemDisplay(stderr
);
800 static FILE *xmlMemoryDumpFile
= NULL
;
805 * @fp: a FILE descriptor used as the output file
806 * @nr: number of entries to dump
808 * show a show display of the memory allocated, and dump
809 * the @nr last allocated areas which were not freed
813 xmlMemShow(FILE *fp
, int nr ATTRIBUTE_UNUSED
)
820 fprintf(fp
," MEMORY ALLOCATED : %lu, MAX was %lu\n",
821 debugMemSize
, debugMaxMemSize
);
823 xmlMutexLock(&xmlMemMutex
);
825 fprintf(fp
,"NUMBER SIZE TYPE WHERE\n");
827 while ((p
) && nr
> 0) {
828 fprintf(fp
,"%6lu %6lu ",p
->mh_number
,(unsigned long)p
->mh_size
);
829 switch (p
->mh_type
) {
830 case STRDUP_TYPE
:fprintf(fp
,"strdup() in ");break;
831 case MALLOC_TYPE
:fprintf(fp
,"malloc() in ");break;
832 case MALLOC_ATOMIC_TYPE
:fprintf(fp
,"atomicmalloc() in ");break;
833 case REALLOC_TYPE
:fprintf(fp
,"realloc() in ");break;
834 case REALLOC_ATOMIC_TYPE
:fprintf(fp
,"atomicrealloc() in ");break;
835 default:fprintf(fp
," ??? in ");break;
837 if (p
->mh_file
!= NULL
)
838 fprintf(fp
,"%s(%u)", p
->mh_file
, p
->mh_line
);
839 if (p
->mh_tag
!= MEMTAG
)
840 fprintf(fp
," INVALID");
846 xmlMutexUnlock(&xmlMemMutex
);
847 #endif /* MEM_LIST */
853 * Dump in-extenso the memory blocks allocated to the file .memorylist
862 if (debugMaxMemSize
== 0)
864 dump
= fopen(".memdump", "w");
866 xmlMemoryDumpFile
= stderr
;
867 else xmlMemoryDumpFile
= dump
;
869 xmlMemDisplay(xmlMemoryDumpFile
);
871 if (dump
!= NULL
) fclose(dump
);
872 #endif /* MEM_LIST */
876 /****************************************************************
878 * Initialization Routines *
880 ****************************************************************/
885 * DEPRECATED: Alias for xmlInitParser.
888 xmlInitMemory(void) {
894 * xmlInitMemoryInternal:
896 * Initialize the memory layer.
898 * Returns 0 on success
901 xmlInitMemoryInternal(void) {
904 xmlGenericError(xmlGenericErrorContext
,
905 "xmlInitMemory()\n");
907 xmlInitMutex(&xmlMemMutex
);
909 breakpoint
= getenv("XML_MEM_BREAKPOINT");
910 if (breakpoint
!= NULL
) {
911 sscanf(breakpoint
, "%ud", &xmlMemStopAtBlock
);
913 breakpoint
= getenv("XML_MEM_TRACE");
914 if (breakpoint
!= NULL
) {
915 sscanf(breakpoint
, "%p", &xmlMemTraceBlockAt
);
919 xmlGenericError(xmlGenericErrorContext
,
920 "xmlInitMemory() Ok\n");
927 * DEPRECATED: This function is a no-op. Call xmlCleanupParser
928 * to free global state but see the warnings there. xmlCleanupParser
929 * should be only called once at program exit. In most cases, you don't
930 * have call cleanup functions at all.
933 xmlCleanupMemory(void) {
937 * xmlCleanupMemoryInternal:
939 * Free up all the memory allocated by the library for its own
940 * use. This should not be called by user level code.
943 xmlCleanupMemoryInternal(void) {
945 xmlGenericError(xmlGenericErrorContext
,
946 "xmlCleanupMemory()\n");
949 xmlCleanupMutex(&xmlMemMutex
);
951 xmlGenericError(xmlGenericErrorContext
,
952 "xmlCleanupMemory() Ok\n");
958 * @freeFunc: the free() function to use
959 * @mallocFunc: the malloc() function to use
960 * @reallocFunc: the realloc() function to use
961 * @strdupFunc: the strdup() function to use
963 * Override the default memory access functions with a new set
964 * This has to be called before any other libxml routines !
966 * Should this be blocked if there was already some allocations
969 * Returns 0 on success
972 xmlMemSetup(xmlFreeFunc freeFunc
, xmlMallocFunc mallocFunc
,
973 xmlReallocFunc reallocFunc
, xmlStrdupFunc strdupFunc
) {
975 xmlGenericError(xmlGenericErrorContext
,
978 if (freeFunc
== NULL
)
980 if (mallocFunc
== NULL
)
982 if (reallocFunc
== NULL
)
984 if (strdupFunc
== NULL
)
987 xmlMalloc
= mallocFunc
;
988 xmlMallocAtomic
= mallocFunc
;
989 xmlRealloc
= reallocFunc
;
990 xmlMemStrdup
= strdupFunc
;
992 xmlGenericError(xmlGenericErrorContext
,
993 "xmlMemSetup() Ok\n");
1000 * @freeFunc: place to save the free() function in use
1001 * @mallocFunc: place to save the malloc() function in use
1002 * @reallocFunc: place to save the realloc() function in use
1003 * @strdupFunc: place to save the strdup() function in use
1005 * Provides the memory access functions set currently in use
1007 * Returns 0 on success
1010 xmlMemGet(xmlFreeFunc
*freeFunc
, xmlMallocFunc
*mallocFunc
,
1011 xmlReallocFunc
*reallocFunc
, xmlStrdupFunc
*strdupFunc
) {
1012 if (freeFunc
!= NULL
) *freeFunc
= xmlFree
;
1013 if (mallocFunc
!= NULL
) *mallocFunc
= xmlMalloc
;
1014 if (reallocFunc
!= NULL
) *reallocFunc
= xmlRealloc
;
1015 if (strdupFunc
!= NULL
) *strdupFunc
= xmlMemStrdup
;
1021 * @freeFunc: the free() function to use
1022 * @mallocFunc: the malloc() function to use
1023 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
1024 * @reallocFunc: the realloc() function to use
1025 * @strdupFunc: the strdup() function to use
1027 * Override the default memory access functions with a new set
1028 * This has to be called before any other libxml routines !
1029 * The mallocAtomicFunc is specialized for atomic block
1030 * allocations (i.e. of areas useful for garbage collected memory allocators
1032 * Should this be blocked if there was already some allocations
1035 * Returns 0 on success
1038 xmlGcMemSetup(xmlFreeFunc freeFunc
, xmlMallocFunc mallocFunc
,
1039 xmlMallocFunc mallocAtomicFunc
, xmlReallocFunc reallocFunc
,
1040 xmlStrdupFunc strdupFunc
) {
1042 xmlGenericError(xmlGenericErrorContext
,
1043 "xmlGcMemSetup()\n");
1045 if (freeFunc
== NULL
)
1047 if (mallocFunc
== NULL
)
1049 if (mallocAtomicFunc
== NULL
)
1051 if (reallocFunc
== NULL
)
1053 if (strdupFunc
== NULL
)
1056 xmlMalloc
= mallocFunc
;
1057 xmlMallocAtomic
= mallocAtomicFunc
;
1058 xmlRealloc
= reallocFunc
;
1059 xmlMemStrdup
= strdupFunc
;
1061 xmlGenericError(xmlGenericErrorContext
,
1062 "xmlGcMemSetup() Ok\n");
1069 * @freeFunc: place to save the free() function in use
1070 * @mallocFunc: place to save the malloc() function in use
1071 * @mallocAtomicFunc: place to save the atomic malloc() function in use
1072 * @reallocFunc: place to save the realloc() function in use
1073 * @strdupFunc: place to save the strdup() function in use
1075 * Provides the memory access functions set currently in use
1076 * The mallocAtomicFunc is specialized for atomic block
1077 * allocations (i.e. of areas useful for garbage collected memory allocators
1079 * Returns 0 on success
1082 xmlGcMemGet(xmlFreeFunc
*freeFunc
, xmlMallocFunc
*mallocFunc
,
1083 xmlMallocFunc
*mallocAtomicFunc
, xmlReallocFunc
*reallocFunc
,
1084 xmlStrdupFunc
*strdupFunc
) {
1085 if (freeFunc
!= NULL
) *freeFunc
= xmlFree
;
1086 if (mallocFunc
!= NULL
) *mallocFunc
= xmlMalloc
;
1087 if (mallocAtomicFunc
!= NULL
) *mallocAtomicFunc
= xmlMallocAtomic
;
1088 if (reallocFunc
!= NULL
) *reallocFunc
= xmlRealloc
;
1089 if (strdupFunc
!= NULL
) *strdupFunc
= xmlMemStrdup
;