dbghelp/tests: Fix process kind detection on old Windows machines.
[wine.git] / libs / xml2 / xmlmemory.c
blob892d50c306dc3b94120107ea4c334ceb7d0672aa
1 /*
2 * xmlmemory.c: libxml memory allocator wrapper.
4 * daniel@veillard.com
5 */
7 #define IN_LIBXML
8 #include "libxml.h"
10 #include <string.h>
11 #include <stdlib.h>
12 #include <ctype.h>
13 #include <time.h>
15 /* #define DEBUG_MEMORY */
17 /**
18 * MEM_LIST:
20 * keep track of all allocated blocks for error reporting
21 * Always build the memory list !
23 #ifdef DEBUG_MEMORY_LOCATION
24 #ifndef MEM_LIST
25 #define MEM_LIST /* keep a list of all the allocated memory blocks */
26 #endif
27 #endif
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 static int xmlMemInitialized = 0;
35 static unsigned long debugMemSize = 0;
36 static unsigned long debugMemBlocks = 0;
37 static unsigned long debugMaxMemSize = 0;
38 static xmlMutexPtr xmlMemMutex = NULL;
40 void xmlMallocBreakpoint(void);
42 /************************************************************************
43 * *
44 * Macros, variables and associated types *
45 * *
46 ************************************************************************/
48 #if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
49 #ifdef xmlMalloc
50 #undef xmlMalloc
51 #endif
52 #ifdef xmlRealloc
53 #undef xmlRealloc
54 #endif
55 #ifdef xmlMemStrdup
56 #undef xmlMemStrdup
57 #endif
58 #endif
61 * Each of the blocks allocated begin with a header containing information
64 #define MEMTAG 0x5aa5U
66 #define MALLOC_TYPE 1
67 #define REALLOC_TYPE 2
68 #define STRDUP_TYPE 3
69 #define MALLOC_ATOMIC_TYPE 4
70 #define REALLOC_ATOMIC_TYPE 5
72 typedef struct memnod {
73 unsigned int mh_tag;
74 unsigned int mh_type;
75 unsigned long mh_number;
76 size_t mh_size;
77 #ifdef MEM_LIST
78 struct memnod *mh_next;
79 struct memnod *mh_prev;
80 #endif
81 const char *mh_file;
82 unsigned int mh_line;
83 } MEMHDR;
86 #ifdef SUN4
87 #define ALIGN_SIZE 16
88 #else
89 #define ALIGN_SIZE sizeof(double)
90 #endif
91 #define HDR_SIZE sizeof(MEMHDR)
92 #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
93 / ALIGN_SIZE ) * ALIGN_SIZE)
95 #define MAX_SIZE_T ((size_t)-1)
97 #define CLIENT_2_HDR(a) ((void *) (((char *) (a)) - RESERVE_SIZE))
98 #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
101 static unsigned int block=0;
102 static unsigned int xmlMemStopAtBlock = 0;
103 static void *xmlMemTraceBlockAt = NULL;
104 #ifdef MEM_LIST
105 static MEMHDR *memlist = NULL;
106 #endif
108 static void debugmem_tag_error(void *addr);
109 #ifdef MEM_LIST
110 static void debugmem_list_add(MEMHDR *);
111 static void debugmem_list_delete(MEMHDR *);
112 #endif
113 #define Mem_Tag_Err(a) debugmem_tag_error(a);
115 #ifndef TEST_POINT
116 #define TEST_POINT
117 #endif
120 * xmlMallocBreakpoint:
122 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
123 * number reaches the specified value this function is called. One need to add a breakpoint
124 * to it to get the context in which the given block is allocated.
127 void
128 xmlMallocBreakpoint(void) {
129 xmlGenericError(xmlGenericErrorContext,
130 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
134 * xmlMallocLoc:
135 * @size: an int specifying the size in byte to allocate.
136 * @file: the file name or NULL
137 * @line: the line number
139 * a malloc() equivalent, with logging of the allocation info.
141 * Returns a pointer to the allocated area or NULL in case of lack of memory.
144 void *
145 xmlMallocLoc(size_t size, const char * file, int line)
147 MEMHDR *p;
148 void *ret;
150 if (!xmlMemInitialized) xmlInitMemory();
151 #ifdef DEBUG_MEMORY
152 xmlGenericError(xmlGenericErrorContext,
153 "Malloc(%d)\n",size);
154 #endif
156 TEST_POINT
158 if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
159 xmlGenericError(xmlGenericErrorContext,
160 "xmlMallocLoc : Unsigned overflow\n");
161 xmlMemoryDump();
162 return(NULL);
165 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
167 if (!p) {
168 xmlGenericError(xmlGenericErrorContext,
169 "xmlMallocLoc : Out of free space\n");
170 xmlMemoryDump();
171 return(NULL);
173 p->mh_tag = MEMTAG;
174 p->mh_size = size;
175 p->mh_type = MALLOC_TYPE;
176 p->mh_file = file;
177 p->mh_line = line;
178 xmlMutexLock(xmlMemMutex);
179 p->mh_number = ++block;
180 debugMemSize += size;
181 debugMemBlocks++;
182 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
183 #ifdef MEM_LIST
184 debugmem_list_add(p);
185 #endif
186 xmlMutexUnlock(xmlMemMutex);
188 #ifdef DEBUG_MEMORY
189 xmlGenericError(xmlGenericErrorContext,
190 "Malloc(%d) Ok\n",size);
191 #endif
193 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
195 ret = HDR_2_CLIENT(p);
197 if (xmlMemTraceBlockAt == ret) {
198 xmlGenericError(xmlGenericErrorContext,
199 "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
200 (long unsigned)size);
201 xmlMallocBreakpoint();
204 TEST_POINT
206 return(ret);
210 * xmlMallocAtomicLoc:
211 * @size: an unsigned int specifying the size in byte to allocate.
212 * @file: the file name or NULL
213 * @line: the line number
215 * a malloc() equivalent, with logging of the allocation info.
217 * Returns a pointer to the allocated area or NULL in case of lack of memory.
220 void *
221 xmlMallocAtomicLoc(size_t size, const char * file, int line)
223 MEMHDR *p;
224 void *ret;
226 if (!xmlMemInitialized) xmlInitMemory();
227 #ifdef DEBUG_MEMORY
228 xmlGenericError(xmlGenericErrorContext,
229 "Malloc(%d)\n",size);
230 #endif
232 TEST_POINT
234 if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
235 xmlGenericError(xmlGenericErrorContext,
236 "xmlMallocAtomicLoc : Unsigned overflow\n");
237 xmlMemoryDump();
238 return(NULL);
241 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
243 if (!p) {
244 xmlGenericError(xmlGenericErrorContext,
245 "xmlMallocAtomicLoc : Out of free space\n");
246 xmlMemoryDump();
247 return(NULL);
249 p->mh_tag = MEMTAG;
250 p->mh_size = size;
251 p->mh_type = MALLOC_ATOMIC_TYPE;
252 p->mh_file = file;
253 p->mh_line = line;
254 xmlMutexLock(xmlMemMutex);
255 p->mh_number = ++block;
256 debugMemSize += size;
257 debugMemBlocks++;
258 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
259 #ifdef MEM_LIST
260 debugmem_list_add(p);
261 #endif
262 xmlMutexUnlock(xmlMemMutex);
264 #ifdef DEBUG_MEMORY
265 xmlGenericError(xmlGenericErrorContext,
266 "Malloc(%d) Ok\n",size);
267 #endif
269 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
271 ret = HDR_2_CLIENT(p);
273 if (xmlMemTraceBlockAt == ret) {
274 xmlGenericError(xmlGenericErrorContext,
275 "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
276 (long unsigned)size);
277 xmlMallocBreakpoint();
280 TEST_POINT
282 return(ret);
285 * xmlMemMalloc:
286 * @size: an int specifying the size in byte to allocate.
288 * a malloc() equivalent, with logging of the allocation info.
290 * Returns a pointer to the allocated area or NULL in case of lack of memory.
293 void *
294 xmlMemMalloc(size_t size)
296 return(xmlMallocLoc(size, "none", 0));
300 * xmlReallocLoc:
301 * @ptr: the initial memory block pointer
302 * @size: an int specifying the size in byte to allocate.
303 * @file: the file name or NULL
304 * @line: the line number
306 * a realloc() equivalent, with logging of the allocation info.
308 * Returns a pointer to the allocated area or NULL in case of lack of memory.
311 void *
312 xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
314 MEMHDR *p, *tmp;
315 unsigned long number;
316 #ifdef DEBUG_MEMORY
317 size_t oldsize;
318 #endif
320 if (ptr == NULL)
321 return(xmlMallocLoc(size, file, line));
323 if (!xmlMemInitialized) xmlInitMemory();
324 TEST_POINT
326 p = CLIENT_2_HDR(ptr);
327 number = p->mh_number;
328 if (xmlMemStopAtBlock == number) xmlMallocBreakpoint();
329 if (p->mh_tag != MEMTAG) {
330 Mem_Tag_Err(p);
331 goto error;
333 p->mh_tag = ~MEMTAG;
334 xmlMutexLock(xmlMemMutex);
335 debugMemSize -= p->mh_size;
336 debugMemBlocks--;
337 #ifdef DEBUG_MEMORY
338 oldsize = p->mh_size;
339 #endif
340 #ifdef MEM_LIST
341 debugmem_list_delete(p);
342 #endif
343 xmlMutexUnlock(xmlMemMutex);
345 if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
346 xmlGenericError(xmlGenericErrorContext,
347 "xmlReallocLoc : Unsigned overflow\n");
348 xmlMemoryDump();
349 return(NULL);
352 tmp = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
353 if (!tmp) {
354 free(p);
355 goto error;
357 p = tmp;
358 if (xmlMemTraceBlockAt == ptr) {
359 xmlGenericError(xmlGenericErrorContext,
360 "%p : Realloced(%lu -> %lu) Ok\n",
361 xmlMemTraceBlockAt, (long unsigned)p->mh_size,
362 (long unsigned)size);
363 xmlMallocBreakpoint();
365 p->mh_tag = MEMTAG;
366 p->mh_number = number;
367 p->mh_type = REALLOC_TYPE;
368 p->mh_size = size;
369 p->mh_file = file;
370 p->mh_line = line;
371 xmlMutexLock(xmlMemMutex);
372 debugMemSize += size;
373 debugMemBlocks++;
374 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
375 #ifdef MEM_LIST
376 debugmem_list_add(p);
377 #endif
378 xmlMutexUnlock(xmlMemMutex);
380 TEST_POINT
382 #ifdef DEBUG_MEMORY
383 xmlGenericError(xmlGenericErrorContext,
384 "Realloced(%d to %d) Ok\n", oldsize, size);
385 #endif
386 return(HDR_2_CLIENT(p));
388 error:
389 return(NULL);
393 * xmlMemRealloc:
394 * @ptr: the initial memory block pointer
395 * @size: an int specifying the size in byte to allocate.
397 * a realloc() equivalent, with logging of the allocation info.
399 * Returns a pointer to the allocated area or NULL in case of lack of memory.
402 void *
403 xmlMemRealloc(void *ptr,size_t size) {
404 return(xmlReallocLoc(ptr, size, "none", 0));
408 * xmlMemFree:
409 * @ptr: the memory block pointer
411 * a free() equivalent, with error checking.
413 void
414 xmlMemFree(void *ptr)
416 MEMHDR *p;
417 char *target;
418 #ifdef DEBUG_MEMORY
419 size_t size;
420 #endif
422 if (ptr == NULL)
423 return;
425 if (ptr == (void *) -1) {
426 xmlGenericError(xmlGenericErrorContext,
427 "trying to free pointer from freed area\n");
428 goto error;
431 if (xmlMemTraceBlockAt == ptr) {
432 xmlGenericError(xmlGenericErrorContext,
433 "%p : Freed()\n", xmlMemTraceBlockAt);
434 xmlMallocBreakpoint();
437 TEST_POINT
439 target = (char *) ptr;
441 p = CLIENT_2_HDR(ptr);
442 if (p->mh_tag != MEMTAG) {
443 Mem_Tag_Err(p);
444 goto error;
446 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
447 p->mh_tag = ~MEMTAG;
448 memset(target, -1, p->mh_size);
449 xmlMutexLock(xmlMemMutex);
450 debugMemSize -= p->mh_size;
451 debugMemBlocks--;
452 #ifdef DEBUG_MEMORY
453 size = p->mh_size;
454 #endif
455 #ifdef MEM_LIST
456 debugmem_list_delete(p);
457 #endif
458 xmlMutexUnlock(xmlMemMutex);
460 free(p);
462 TEST_POINT
464 #ifdef DEBUG_MEMORY
465 xmlGenericError(xmlGenericErrorContext,
466 "Freed(%d) Ok\n", size);
467 #endif
469 return;
471 error:
472 xmlGenericError(xmlGenericErrorContext,
473 "xmlMemFree(%p) error\n", ptr);
474 xmlMallocBreakpoint();
475 return;
479 * xmlMemStrdupLoc:
480 * @str: the initial string pointer
481 * @file: the file name or NULL
482 * @line: the line number
484 * a strdup() equivalent, with logging of the allocation info.
486 * Returns a pointer to the new string or NULL if allocation error occurred.
489 char *
490 xmlMemStrdupLoc(const char *str, const char *file, int line)
492 char *s;
493 size_t size = strlen(str) + 1;
494 MEMHDR *p;
496 if (!xmlMemInitialized) xmlInitMemory();
497 TEST_POINT
499 if (size > (MAX_SIZE_T - RESERVE_SIZE)) {
500 xmlGenericError(xmlGenericErrorContext,
501 "xmlMemStrdupLoc : Unsigned overflow\n");
502 xmlMemoryDump();
503 return(NULL);
506 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
507 if (!p) {
508 goto error;
510 p->mh_tag = MEMTAG;
511 p->mh_size = size;
512 p->mh_type = STRDUP_TYPE;
513 p->mh_file = file;
514 p->mh_line = line;
515 xmlMutexLock(xmlMemMutex);
516 p->mh_number = ++block;
517 debugMemSize += size;
518 debugMemBlocks++;
519 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
520 #ifdef MEM_LIST
521 debugmem_list_add(p);
522 #endif
523 xmlMutexUnlock(xmlMemMutex);
525 s = (char *) HDR_2_CLIENT(p);
527 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
529 strcpy(s,str);
531 TEST_POINT
533 if (xmlMemTraceBlockAt == s) {
534 xmlGenericError(xmlGenericErrorContext,
535 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
536 xmlMallocBreakpoint();
539 return(s);
541 error:
542 return(NULL);
546 * xmlMemoryStrdup:
547 * @str: the initial string pointer
549 * a strdup() equivalent, with logging of the allocation info.
551 * Returns a pointer to the new string or NULL if allocation error occurred.
554 char *
555 xmlMemoryStrdup(const char *str) {
556 return(xmlMemStrdupLoc(str, "none", 0));
560 * xmlMemUsed:
562 * Provides the amount of memory currently allocated
564 * Returns an int representing the amount of memory allocated.
568 xmlMemUsed(void) {
569 int res;
571 xmlMutexLock(xmlMemMutex);
572 res = debugMemSize;
573 xmlMutexUnlock(xmlMemMutex);
574 return(res);
578 * xmlMemBlocks:
580 * Provides the number of memory areas currently allocated
582 * Returns an int representing the number of blocks
586 xmlMemBlocks(void) {
587 int res;
589 xmlMutexLock(xmlMemMutex);
590 res = debugMemBlocks;
591 xmlMutexUnlock(xmlMemMutex);
592 return(res);
595 #ifdef MEM_LIST
597 * xmlMemContentShow:
598 * @fp: a FILE descriptor used as the output file
599 * @p: a memory block header
601 * tries to show some content from the memory block
604 static void
605 xmlMemContentShow(FILE *fp, MEMHDR *p)
607 int i,j,k,len;
608 const char *buf;
610 if (p == NULL) {
611 fprintf(fp, " NULL");
612 return;
614 len = p->mh_size;
615 buf = (const char *) HDR_2_CLIENT(p);
617 for (i = 0;i < len;i++) {
618 if (buf[i] == 0) break;
619 if (!isprint((unsigned char) buf[i])) break;
621 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
622 if (len >= 4) {
623 MEMHDR *q;
624 void *cur;
626 for (j = 0;(j < len -3) && (j < 40);j += 4) {
627 cur = *((void **) &buf[j]);
628 q = CLIENT_2_HDR(cur);
629 p = memlist;
630 k = 0;
631 while (p != NULL) {
632 if (p == q) break;
633 p = p->mh_next;
634 if (k++ > 100) break;
636 if ((p != NULL) && (p == q)) {
637 fprintf(fp, " pointer to #%lu at index %d",
638 p->mh_number, j);
639 return;
643 } else if ((i == 0) && (buf[i] == 0)) {
644 fprintf(fp," null");
645 } else {
646 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
647 else {
648 fprintf(fp," [");
649 for (j = 0;j < i;j++)
650 fprintf(fp,"%c", buf[j]);
651 fprintf(fp,"]");
655 #endif
658 * xmlMemDisplayLast:
659 * @fp: a FILE descriptor used as the output file, if NULL, the result is
660 * written to the file .memorylist
661 * @nbBytes: the amount of memory to dump
663 * the last nbBytes of memory allocated and not freed, useful for dumping
664 * the memory left allocated between two places at runtime.
667 void
668 xmlMemDisplayLast(FILE *fp, long nbBytes)
670 #ifdef MEM_LIST
671 MEMHDR *p;
672 unsigned idx;
673 int nb = 0;
674 #endif
675 FILE *old_fp = fp;
677 if (nbBytes <= 0)
678 return;
680 if (fp == NULL) {
681 fp = fopen(".memorylist", "w");
682 if (fp == NULL)
683 return;
686 #ifdef MEM_LIST
687 fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
688 nbBytes, debugMemSize, debugMaxMemSize);
689 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
690 idx = 0;
691 xmlMutexLock(xmlMemMutex);
692 p = memlist;
693 while ((p) && (nbBytes > 0)) {
694 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
695 (unsigned long)p->mh_size);
696 switch (p->mh_type) {
697 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
698 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
699 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
700 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
701 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
702 default:
703 fprintf(fp,"Unknown memory block, may be corrupted");
704 xmlMutexUnlock(xmlMemMutex);
705 if (old_fp == NULL)
706 fclose(fp);
707 return;
709 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
710 if (p->mh_tag != MEMTAG)
711 fprintf(fp," INVALID");
712 nb++;
713 if (nb < 100)
714 xmlMemContentShow(fp, p);
715 else
716 fprintf(fp," skip");
718 fprintf(fp,"\n");
719 nbBytes -= (unsigned long)p->mh_size;
720 p = p->mh_next;
722 xmlMutexUnlock(xmlMemMutex);
723 #else
724 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
725 #endif
726 if (old_fp == NULL)
727 fclose(fp);
731 * xmlMemDisplay:
732 * @fp: a FILE descriptor used as the output file, if NULL, the result is
733 * written to the file .memorylist
735 * show in-extenso the memory blocks allocated
738 void
739 xmlMemDisplay(FILE *fp)
741 #ifdef MEM_LIST
742 MEMHDR *p;
743 unsigned idx;
744 int nb = 0;
745 time_t currentTime;
746 char buf[500];
747 struct tm * tstruct;
748 #endif
749 FILE *old_fp = fp;
751 if (fp == NULL) {
752 fp = fopen(".memorylist", "w");
753 if (fp == NULL)
754 return;
757 #ifdef MEM_LIST
758 currentTime = time(NULL);
759 tstruct = localtime(&currentTime);
760 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
761 fprintf(fp," %s\n\n", buf);
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;
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");
795 fprintf(fp,"\n");
796 p = p->mh_next;
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);
806 #ifdef MEM_LIST
808 static void debugmem_list_add(MEMHDR *p)
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
820 static void debugmem_list_delete(MEMHDR *p)
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
833 #endif
836 * debugmem_tag_error:
838 * internal error function.
841 static void debugmem_tag_error(void *p)
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
851 #ifdef MEM_LIST
852 static FILE *xmlMemoryDumpFile = NULL;
853 #endif
856 * xmlMemShow:
857 * @fp: a FILE descriptor used as the output file
858 * @nr: number of entries to dump
860 * show a show display of the memory allocated, and dump
861 * the @nr last allocated areas which were not freed
864 void
865 xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
867 #ifdef MEM_LIST
868 MEMHDR *p;
869 #endif
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;
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;
899 xmlMutexUnlock(xmlMemMutex);
900 #endif /* MEM_LIST */
904 * xmlMemoryDump:
906 * Dump in-extenso the memory blocks allocated to the file .memorylist
909 void
910 xmlMemoryDump(void)
912 #ifdef MEM_LIST
913 FILE *dump;
915 if (debugMaxMemSize == 0)
916 return;
917 dump = fopen(".memdump", "w");
918 if (dump == NULL)
919 xmlMemoryDumpFile = stderr;
920 else xmlMemoryDumpFile = dump;
922 xmlMemDisplay(xmlMemoryDumpFile);
924 if (dump != NULL) fclose(dump);
925 #endif /* MEM_LIST */
929 /****************************************************************
931 * Initialization Routines *
933 ****************************************************************/
936 * xmlInitMemory:
938 * DEPRECATED: This function will be made private. Call xmlInitParser to
939 * initialize the library.
941 * Initialize the memory layer.
943 * Returns 0 on success
946 xmlInitMemory(void)
948 char *breakpoint;
949 #ifdef DEBUG_MEMORY
950 xmlGenericError(xmlGenericErrorContext,
951 "xmlInitMemory()\n");
952 #endif
954 This is really not good code (see Bug 130419). Suggestions for
955 improvement will be welcome!
957 if (xmlMemInitialized) return(-1);
958 xmlMemInitialized = 1;
959 xmlMemMutex = xmlNewMutex();
961 breakpoint = getenv("XML_MEM_BREAKPOINT");
962 if (breakpoint != NULL) {
963 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
965 breakpoint = getenv("XML_MEM_TRACE");
966 if (breakpoint != NULL) {
967 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
970 #ifdef DEBUG_MEMORY
971 xmlGenericError(xmlGenericErrorContext,
972 "xmlInitMemory() Ok\n");
973 #endif
974 return(0);
978 * xmlCleanupMemory:
980 * DEPRECATED: This function will be made private. Call xmlCleanupParser
981 * to free global state but see the warnings there. xmlCleanupParser
982 * should be only called once at program exit. In most cases, you don't
983 * have call cleanup functions at all.
985 * Free up all the memory allocated by the library for its own
986 * use. This should not be called by user level code.
988 void
989 xmlCleanupMemory(void) {
990 #ifdef DEBUG_MEMORY
991 xmlGenericError(xmlGenericErrorContext,
992 "xmlCleanupMemory()\n");
993 #endif
994 if (xmlMemInitialized == 0)
995 return;
997 xmlFreeMutex(xmlMemMutex);
998 xmlMemMutex = NULL;
999 xmlMemInitialized = 0;
1000 #ifdef DEBUG_MEMORY
1001 xmlGenericError(xmlGenericErrorContext,
1002 "xmlCleanupMemory() Ok\n");
1003 #endif
1007 * xmlMemSetup:
1008 * @freeFunc: the free() function to use
1009 * @mallocFunc: the malloc() function to use
1010 * @reallocFunc: the realloc() function to use
1011 * @strdupFunc: the strdup() function to use
1013 * Override the default memory access functions with a new set
1014 * This has to be called before any other libxml routines !
1016 * Should this be blocked if there was already some allocations
1017 * done ?
1019 * Returns 0 on success
1022 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1023 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
1024 #ifdef DEBUG_MEMORY
1025 xmlGenericError(xmlGenericErrorContext,
1026 "xmlMemSetup()\n");
1027 #endif
1028 if (freeFunc == NULL)
1029 return(-1);
1030 if (mallocFunc == NULL)
1031 return(-1);
1032 if (reallocFunc == NULL)
1033 return(-1);
1034 if (strdupFunc == NULL)
1035 return(-1);
1036 xmlFree = freeFunc;
1037 xmlMalloc = mallocFunc;
1038 xmlMallocAtomic = mallocFunc;
1039 xmlRealloc = reallocFunc;
1040 xmlMemStrdup = strdupFunc;
1041 #ifdef DEBUG_MEMORY
1042 xmlGenericError(xmlGenericErrorContext,
1043 "xmlMemSetup() Ok\n");
1044 #endif
1045 return(0);
1049 * xmlMemGet:
1050 * @freeFunc: place to save the free() function in use
1051 * @mallocFunc: place to save the malloc() function in use
1052 * @reallocFunc: place to save the realloc() function in use
1053 * @strdupFunc: place to save the strdup() function in use
1055 * Provides the memory access functions set currently in use
1057 * Returns 0 on success
1060 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1061 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
1062 if (freeFunc != NULL) *freeFunc = xmlFree;
1063 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1064 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1065 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1066 return(0);
1070 * xmlGcMemSetup:
1071 * @freeFunc: the free() function to use
1072 * @mallocFunc: the malloc() function to use
1073 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
1074 * @reallocFunc: the realloc() function to use
1075 * @strdupFunc: the strdup() function to use
1077 * Override the default memory access functions with a new set
1078 * This has to be called before any other libxml routines !
1079 * The mallocAtomicFunc is specialized for atomic block
1080 * allocations (i.e. of areas useful for garbage collected memory allocators
1082 * Should this be blocked if there was already some allocations
1083 * done ?
1085 * Returns 0 on success
1088 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1089 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
1090 xmlStrdupFunc strdupFunc) {
1091 #ifdef DEBUG_MEMORY
1092 xmlGenericError(xmlGenericErrorContext,
1093 "xmlGcMemSetup()\n");
1094 #endif
1095 if (freeFunc == NULL)
1096 return(-1);
1097 if (mallocFunc == NULL)
1098 return(-1);
1099 if (mallocAtomicFunc == NULL)
1100 return(-1);
1101 if (reallocFunc == NULL)
1102 return(-1);
1103 if (strdupFunc == NULL)
1104 return(-1);
1105 xmlFree = freeFunc;
1106 xmlMalloc = mallocFunc;
1107 xmlMallocAtomic = mallocAtomicFunc;
1108 xmlRealloc = reallocFunc;
1109 xmlMemStrdup = strdupFunc;
1110 #ifdef DEBUG_MEMORY
1111 xmlGenericError(xmlGenericErrorContext,
1112 "xmlGcMemSetup() Ok\n");
1113 #endif
1114 return(0);
1118 * xmlGcMemGet:
1119 * @freeFunc: place to save the free() function in use
1120 * @mallocFunc: place to save the malloc() function in use
1121 * @mallocAtomicFunc: place to save the atomic malloc() function in use
1122 * @reallocFunc: place to save the realloc() function in use
1123 * @strdupFunc: place to save the strdup() function in use
1125 * Provides the memory access functions set currently in use
1126 * The mallocAtomicFunc is specialized for atomic block
1127 * allocations (i.e. of areas useful for garbage collected memory allocators
1129 * Returns 0 on success
1132 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1133 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
1134 xmlStrdupFunc *strdupFunc) {
1135 if (freeFunc != NULL) *freeFunc = xmlFree;
1136 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1137 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
1138 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1139 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1140 return(0);