Annotation of embedaddon/libxml2/xmlmemory.c, revision 1.1.1.1
1.1 misho 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:
113: #define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
114: #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
115:
116:
117: static unsigned int block=0;
118: static unsigned int xmlMemStopAtBlock = 0;
119: static void *xmlMemTraceBlockAt = NULL;
120: #ifdef MEM_LIST
121: static MEMHDR *memlist = NULL;
122: #endif
123:
124: static void debugmem_tag_error(void *addr);
125: #ifdef MEM_LIST
126: static void debugmem_list_add(MEMHDR *);
127: static void debugmem_list_delete(MEMHDR *);
128: #endif
129: #define Mem_Tag_Err(a) debugmem_tag_error(a);
130:
131: #ifndef TEST_POINT
132: #define TEST_POINT
133: #endif
134:
135: /**
136: * xmlMallocBreakpoint:
137: *
138: * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
139: * number reaches the specified value this function is called. One need to add a breakpoint
140: * to it to get the context in which the given block is allocated.
141: */
142:
143: void
144: xmlMallocBreakpoint(void) {
145: xmlGenericError(xmlGenericErrorContext,
146: "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
147: }
148:
149: /**
150: * xmlMallocLoc:
151: * @size: an int specifying the size in byte to allocate.
152: * @file: the file name or NULL
153: * @line: the line number
154: *
155: * a malloc() equivalent, with logging of the allocation info.
156: *
157: * Returns a pointer to the allocated area or NULL in case of lack of memory.
158: */
159:
160: void *
161: xmlMallocLoc(size_t size, const char * file, int line)
162: {
163: MEMHDR *p;
164: void *ret;
165:
166: if (!xmlMemInitialized) xmlInitMemory();
167: #ifdef DEBUG_MEMORY
168: xmlGenericError(xmlGenericErrorContext,
169: "Malloc(%d)\n",size);
170: #endif
171:
172: TEST_POINT
173:
174: p = (MEMHDR *) malloc(RESERVE_SIZE+size);
175:
176: if (!p) {
177: xmlGenericError(xmlGenericErrorContext,
178: "xmlMallocLoc : Out of free space\n");
179: xmlMemoryDump();
180: return(NULL);
181: }
182: p->mh_tag = MEMTAG;
183: p->mh_size = size;
184: p->mh_type = MALLOC_TYPE;
185: p->mh_file = file;
186: p->mh_line = line;
187: xmlMutexLock(xmlMemMutex);
188: p->mh_number = ++block;
189: debugMemSize += size;
190: debugMemBlocks++;
191: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
192: #ifdef MEM_LIST
193: debugmem_list_add(p);
194: #endif
195: xmlMutexUnlock(xmlMemMutex);
196:
197: #ifdef DEBUG_MEMORY
198: xmlGenericError(xmlGenericErrorContext,
199: "Malloc(%d) Ok\n",size);
200: #endif
201:
202: if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
203:
204: ret = HDR_2_CLIENT(p);
205:
206: if (xmlMemTraceBlockAt == ret) {
207: xmlGenericError(xmlGenericErrorContext,
208: "%p : Malloc(%ld) Ok\n", xmlMemTraceBlockAt, size);
209: xmlMallocBreakpoint();
210: }
211:
212: TEST_POINT
213:
214: return(ret);
215: }
216:
217: /**
218: * xmlMallocAtomicLoc:
219: * @size: an int specifying the size in byte to allocate.
220: * @file: the file name or NULL
221: * @line: the line number
222: *
223: * a malloc() equivalent, with logging of the allocation info.
224: *
225: * Returns a pointer to the allocated area or NULL in case of lack of memory.
226: */
227:
228: void *
229: xmlMallocAtomicLoc(size_t size, const char * file, int line)
230: {
231: MEMHDR *p;
232: void *ret;
233:
234: if (!xmlMemInitialized) xmlInitMemory();
235: #ifdef DEBUG_MEMORY
236: xmlGenericError(xmlGenericErrorContext,
237: "Malloc(%d)\n",size);
238: #endif
239:
240: TEST_POINT
241:
242: p = (MEMHDR *) malloc(RESERVE_SIZE+size);
243:
244: if (!p) {
245: xmlGenericError(xmlGenericErrorContext,
246: "xmlMallocLoc : Out of free space\n");
247: xmlMemoryDump();
248: return(NULL);
249: }
250: p->mh_tag = MEMTAG;
251: p->mh_size = size;
252: p->mh_type = MALLOC_ATOMIC_TYPE;
253: p->mh_file = file;
254: p->mh_line = line;
255: xmlMutexLock(xmlMemMutex);
256: p->mh_number = ++block;
257: debugMemSize += size;
258: debugMemBlocks++;
259: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
260: #ifdef MEM_LIST
261: debugmem_list_add(p);
262: #endif
263: xmlMutexUnlock(xmlMemMutex);
264:
265: #ifdef DEBUG_MEMORY
266: xmlGenericError(xmlGenericErrorContext,
267: "Malloc(%d) Ok\n",size);
268: #endif
269:
270: if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
271:
272: ret = HDR_2_CLIENT(p);
273:
274: if (xmlMemTraceBlockAt == ret) {
275: xmlGenericError(xmlGenericErrorContext,
276: "%p : Malloc(%ld) Ok\n", xmlMemTraceBlockAt, size);
277: xmlMallocBreakpoint();
278: }
279:
280: TEST_POINT
281:
282: return(ret);
283: }
284: /**
285: * xmlMemMalloc:
286: * @size: an int specifying the size in byte to allocate.
287: *
288: * a malloc() equivalent, with logging of the allocation info.
289: *
290: * Returns a pointer to the allocated area or NULL in case of lack of memory.
291: */
292:
293: void *
294: xmlMemMalloc(size_t size)
295: {
296: return(xmlMallocLoc(size, "none", 0));
297: }
298:
299: /**
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
305: *
306: * a realloc() equivalent, with logging of the allocation info.
307: *
308: * Returns a pointer to the allocated area or NULL in case of lack of memory.
309: */
310:
311: void *
312: xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
313: {
314: MEMHDR *p;
315: unsigned long number;
316: #ifdef DEBUG_MEMORY
317: size_t oldsize;
318: #endif
319:
320: if (ptr == NULL)
321: return(xmlMallocLoc(size, file, line));
322:
323: if (!xmlMemInitialized) xmlInitMemory();
324: TEST_POINT
325:
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;
332: }
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);
344:
345: p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
346: if (!p) {
347: goto error;
348: }
349: if (xmlMemTraceBlockAt == ptr) {
350: xmlGenericError(xmlGenericErrorContext,
351: "%p : Realloced(%ld -> %ld) Ok\n",
352: xmlMemTraceBlockAt, p->mh_size, size);
353: xmlMallocBreakpoint();
354: }
355: p->mh_tag = MEMTAG;
356: p->mh_number = number;
357: p->mh_type = REALLOC_TYPE;
358: p->mh_size = size;
359: p->mh_file = file;
360: p->mh_line = line;
361: xmlMutexLock(xmlMemMutex);
362: debugMemSize += size;
363: debugMemBlocks++;
364: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
365: #ifdef MEM_LIST
366: debugmem_list_add(p);
367: #endif
368: xmlMutexUnlock(xmlMemMutex);
369:
370: TEST_POINT
371:
372: #ifdef DEBUG_MEMORY
373: xmlGenericError(xmlGenericErrorContext,
374: "Realloced(%d to %d) Ok\n", oldsize, size);
375: #endif
376: return(HDR_2_CLIENT(p));
377:
378: error:
379: return(NULL);
380: }
381:
382: /**
383: * xmlMemRealloc:
384: * @ptr: the initial memory block pointer
385: * @size: an int specifying the size in byte to allocate.
386: *
387: * a realloc() equivalent, with logging of the allocation info.
388: *
389: * Returns a pointer to the allocated area or NULL in case of lack of memory.
390: */
391:
392: void *
393: xmlMemRealloc(void *ptr,size_t size) {
394: return(xmlReallocLoc(ptr, size, "none", 0));
395: }
396:
397: /**
398: * xmlMemFree:
399: * @ptr: the memory block pointer
400: *
401: * a free() equivalent, with error checking.
402: */
403: void
404: xmlMemFree(void *ptr)
405: {
406: MEMHDR *p;
407: char *target;
408: #ifdef DEBUG_MEMORY
409: size_t size;
410: #endif
411:
412: if (ptr == NULL)
413: return;
414:
415: if (ptr == (void *) -1) {
416: xmlGenericError(xmlGenericErrorContext,
417: "trying to free pointer from freed area\n");
418: goto error;
419: }
420:
421: if (xmlMemTraceBlockAt == ptr) {
422: xmlGenericError(xmlGenericErrorContext,
423: "%p : Freed()\n", xmlMemTraceBlockAt);
424: xmlMallocBreakpoint();
425: }
426:
427: TEST_POINT
428:
429: target = (char *) ptr;
430:
431: p = CLIENT_2_HDR(ptr);
432: if (p->mh_tag != MEMTAG) {
433: Mem_Tag_Err(p);
434: goto error;
435: }
436: if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
437: p->mh_tag = ~MEMTAG;
438: memset(target, -1, p->mh_size);
439: xmlMutexLock(xmlMemMutex);
440: debugMemSize -= p->mh_size;
441: debugMemBlocks--;
442: #ifdef DEBUG_MEMORY
443: size = p->mh_size;
444: #endif
445: #ifdef MEM_LIST
446: debugmem_list_delete(p);
447: #endif
448: xmlMutexUnlock(xmlMemMutex);
449:
450: free(p);
451:
452: TEST_POINT
453:
454: #ifdef DEBUG_MEMORY
455: xmlGenericError(xmlGenericErrorContext,
456: "Freed(%d) Ok\n", size);
457: #endif
458:
459: return;
460:
461: error:
462: xmlGenericError(xmlGenericErrorContext,
463: "xmlMemFree(%lX) error\n", (unsigned long) ptr);
464: xmlMallocBreakpoint();
465: return;
466: }
467:
468: /**
469: * xmlMemStrdupLoc:
470: * @str: the initial string pointer
471: * @file: the file name or NULL
472: * @line: the line number
473: *
474: * a strdup() equivalent, with logging of the allocation info.
475: *
476: * Returns a pointer to the new string or NULL if allocation error occurred.
477: */
478:
479: char *
480: xmlMemStrdupLoc(const char *str, const char *file, int line)
481: {
482: char *s;
483: size_t size = strlen(str) + 1;
484: MEMHDR *p;
485:
486: if (!xmlMemInitialized) xmlInitMemory();
487: TEST_POINT
488:
489: p = (MEMHDR *) malloc(RESERVE_SIZE+size);
490: if (!p) {
491: goto error;
492: }
493: p->mh_tag = MEMTAG;
494: p->mh_size = size;
495: p->mh_type = STRDUP_TYPE;
496: p->mh_file = file;
497: p->mh_line = line;
498: xmlMutexLock(xmlMemMutex);
499: p->mh_number = ++block;
500: debugMemSize += size;
501: debugMemBlocks++;
502: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
503: #ifdef MEM_LIST
504: debugmem_list_add(p);
505: #endif
506: xmlMutexUnlock(xmlMemMutex);
507:
508: s = (char *) HDR_2_CLIENT(p);
509:
510: if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
511:
512: if (s != NULL)
513: strcpy(s,str);
514: else
515: goto error;
516:
517: TEST_POINT
518:
519: if (xmlMemTraceBlockAt == s) {
520: xmlGenericError(xmlGenericErrorContext,
521: "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
522: xmlMallocBreakpoint();
523: }
524:
525: return(s);
526:
527: error:
528: return(NULL);
529: }
530:
531: /**
532: * xmlMemoryStrdup:
533: * @str: the initial string pointer
534: *
535: * a strdup() equivalent, with logging of the allocation info.
536: *
537: * Returns a pointer to the new string or NULL if allocation error occurred.
538: */
539:
540: char *
541: xmlMemoryStrdup(const char *str) {
542: return(xmlMemStrdupLoc(str, "none", 0));
543: }
544:
545: /**
546: * xmlMemUsed:
547: *
548: * Provides the amount of memory currently allocated
549: *
550: * Returns an int representing the amount of memory allocated.
551: */
552:
553: int
554: xmlMemUsed(void) {
555: return(debugMemSize);
556: }
557:
558: /**
559: * xmlMemBlocks:
560: *
561: * Provides the number of memory areas currently allocated
562: *
563: * Returns an int representing the number of blocks
564: */
565:
566: int
567: xmlMemBlocks(void) {
568: return(debugMemBlocks);
569: }
570:
571: #ifdef MEM_LIST
572: /**
573: * xmlMemContentShow:
574: * @fp: a FILE descriptor used as the output file
575: * @p: a memory block header
576: *
577: * tries to show some content from the memory block
578: */
579:
580: static void
581: xmlMemContentShow(FILE *fp, MEMHDR *p)
582: {
583: int i,j,k,len = p->mh_size;
584: const char *buf = (const char *) HDR_2_CLIENT(p);
585:
586: if (p == NULL) {
587: fprintf(fp, " NULL");
588: return;
589: }
590:
591: for (i = 0;i < len;i++) {
592: if (buf[i] == 0) break;
593: if (!isprint((unsigned char) buf[i])) break;
594: }
595: if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
596: if (len >= 4) {
597: MEMHDR *q;
598: void *cur;
599:
600: for (j = 0;(j < len -3) && (j < 40);j += 4) {
601: cur = *((void **) &buf[j]);
602: q = CLIENT_2_HDR(cur);
603: p = memlist;
604: k = 0;
605: while (p != NULL) {
606: if (p == q) break;
607: p = p->mh_next;
608: if (k++ > 100) break;
609: }
610: if ((p != NULL) && (p == q)) {
611: fprintf(fp, " pointer to #%lu at index %d",
612: p->mh_number, j);
613: return;
614: }
615: }
616: }
617: } else if ((i == 0) && (buf[i] == 0)) {
618: fprintf(fp," null");
619: } else {
620: if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
621: else {
622: fprintf(fp," [");
623: for (j = 0;j < i;j++)
624: fprintf(fp,"%c", buf[j]);
625: fprintf(fp,"]");
626: }
627: }
628: }
629: #endif
630:
631: /**
632: * xmlMemDisplayLast:
633: * @fp: a FILE descriptor used as the output file, if NULL, the result is
634: * written to the file .memorylist
635: * @nbBytes: the amount of memory to dump
636: *
637: * the last nbBytes of memory allocated and not freed, useful for dumping
638: * the memory left allocated between two places at runtime.
639: */
640:
641: void
642: xmlMemDisplayLast(FILE *fp, long nbBytes)
643: {
644: #ifdef MEM_LIST
645: MEMHDR *p;
646: unsigned idx;
647: int nb = 0;
648: #endif
649: FILE *old_fp = fp;
650:
651: if (nbBytes <= 0)
652: return;
653:
654: if (fp == NULL) {
655: fp = fopen(".memorylist", "w");
656: if (fp == NULL)
657: return;
658: }
659:
660: #ifdef MEM_LIST
661: fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
662: nbBytes, debugMemSize, debugMaxMemSize);
663: fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
664: idx = 0;
665: xmlMutexLock(xmlMemMutex);
666: p = memlist;
667: while ((p) && (nbBytes > 0)) {
668: fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
669: (unsigned long)p->mh_size);
670: switch (p->mh_type) {
671: case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
672: case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
673: case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
674: case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
675: case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
676: default:
677: fprintf(fp,"Unknown memory block, may be corrupted");
678: xmlMutexUnlock(xmlMemMutex);
679: if (old_fp == NULL)
680: fclose(fp);
681: return;
682: }
683: if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
684: if (p->mh_tag != MEMTAG)
685: fprintf(fp," INVALID");
686: nb++;
687: if (nb < 100)
688: xmlMemContentShow(fp, p);
689: else
690: fprintf(fp," skip");
691:
692: fprintf(fp,"\n");
693: nbBytes -= (unsigned long)p->mh_size;
694: p = p->mh_next;
695: }
696: xmlMutexUnlock(xmlMemMutex);
697: #else
698: fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
699: #endif
700: if (old_fp == NULL)
701: fclose(fp);
702: }
703:
704: /**
705: * xmlMemDisplay:
706: * @fp: a FILE descriptor used as the output file, if NULL, the result is
707: * written to the file .memorylist
708: *
709: * show in-extenso the memory blocks allocated
710: */
711:
712: void
713: xmlMemDisplay(FILE *fp)
714: {
715: #ifdef MEM_LIST
716: MEMHDR *p;
717: unsigned idx;
718: int nb = 0;
719: #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
720: time_t currentTime;
721: char buf[500];
722: struct tm * tstruct;
723: #endif
724: #endif
725: FILE *old_fp = fp;
726:
727: if (fp == NULL) {
728: fp = fopen(".memorylist", "w");
729: if (fp == NULL)
730: return;
731: }
732:
733: #ifdef MEM_LIST
734: #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
735: currentTime = time(NULL);
736: tstruct = localtime(¤tTime);
737: strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
738: fprintf(fp," %s\n\n", buf);
739: #endif
740:
741:
742: fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
743: debugMemSize, debugMaxMemSize);
744: fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
745: idx = 0;
746: xmlMutexLock(xmlMemMutex);
747: p = memlist;
748: while (p) {
749: fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
750: (unsigned long)p->mh_size);
751: switch (p->mh_type) {
752: case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
753: case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
754: case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
755: case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
756: case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
757: default:
758: fprintf(fp,"Unknown memory block, may be corrupted");
759: xmlMutexUnlock(xmlMemMutex);
760: if (old_fp == NULL)
761: fclose(fp);
762: return;
763: }
764: if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
765: if (p->mh_tag != MEMTAG)
766: fprintf(fp," INVALID");
767: nb++;
768: if (nb < 100)
769: xmlMemContentShow(fp, p);
770: else
771: fprintf(fp," skip");
772:
773: fprintf(fp,"\n");
774: p = p->mh_next;
775: }
776: xmlMutexUnlock(xmlMemMutex);
777: #else
778: fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
779: #endif
780: if (old_fp == NULL)
781: fclose(fp);
782: }
783:
784: #ifdef MEM_LIST
785:
786: static void debugmem_list_add(MEMHDR *p)
787: {
788: p->mh_next = memlist;
789: p->mh_prev = NULL;
790: if (memlist) memlist->mh_prev = p;
791: memlist = p;
792: #ifdef MEM_LIST_DEBUG
793: if (stderr)
794: Mem_Display(stderr);
795: #endif
796: }
797:
798: static void debugmem_list_delete(MEMHDR *p)
799: {
800: if (p->mh_next)
801: p->mh_next->mh_prev = p->mh_prev;
802: if (p->mh_prev)
803: p->mh_prev->mh_next = p->mh_next;
804: else memlist = p->mh_next;
805: #ifdef MEM_LIST_DEBUG
806: if (stderr)
807: Mem_Display(stderr);
808: #endif
809: }
810:
811: #endif
812:
813: /*
814: * debugmem_tag_error:
815: *
816: * internal error function.
817: */
818:
819: static void debugmem_tag_error(void *p)
820: {
821: xmlGenericError(xmlGenericErrorContext,
822: "Memory tag error occurs :%p \n\t bye\n", p);
823: #ifdef MEM_LIST
824: if (stderr)
825: xmlMemDisplay(stderr);
826: #endif
827: }
828:
829: #ifdef MEM_LIST
830: static FILE *xmlMemoryDumpFile = NULL;
831: #endif
832:
833: /**
834: * xmlMemShow:
835: * @fp: a FILE descriptor used as the output file
836: * @nr: number of entries to dump
837: *
838: * show a show display of the memory allocated, and dump
839: * the @nr last allocated areas which were not freed
840: */
841:
842: void
843: xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
844: {
845: #ifdef MEM_LIST
846: MEMHDR *p;
847: #endif
848:
849: if (fp != NULL)
850: fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
851: debugMemSize, debugMaxMemSize);
852: #ifdef MEM_LIST
853: xmlMutexLock(xmlMemMutex);
854: if (nr > 0) {
855: fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
856: p = memlist;
857: while ((p) && nr > 0) {
858: fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
859: switch (p->mh_type) {
860: case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
861: case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
862: case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
863: case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
864: case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
865: default:fprintf(fp," ??? in ");break;
866: }
867: if (p->mh_file != NULL)
868: fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
869: if (p->mh_tag != MEMTAG)
870: fprintf(fp," INVALID");
871: xmlMemContentShow(fp, p);
872: fprintf(fp,"\n");
873: nr--;
874: p = p->mh_next;
875: }
876: }
877: xmlMutexUnlock(xmlMemMutex);
878: #endif /* MEM_LIST */
879: }
880:
881: /**
882: * xmlMemoryDump:
883: *
884: * Dump in-extenso the memory blocks allocated to the file .memorylist
885: */
886:
887: void
888: xmlMemoryDump(void)
889: {
890: #ifdef MEM_LIST
891: FILE *dump;
892:
893: if (debugMaxMemSize == 0)
894: return;
895: dump = fopen(".memdump", "w");
896: if (dump == NULL)
897: xmlMemoryDumpFile = stderr;
898: else xmlMemoryDumpFile = dump;
899:
900: xmlMemDisplay(xmlMemoryDumpFile);
901:
902: if (dump != NULL) fclose(dump);
903: #endif /* MEM_LIST */
904: }
905:
906:
907: /****************************************************************
908: * *
909: * Initialization Routines *
910: * *
911: ****************************************************************/
912:
913: /**
914: * xmlInitMemory:
915: *
916: * Initialize the memory layer.
917: *
918: * Returns 0 on success
919: */
920: int
921: xmlInitMemory(void)
922: {
923: #ifdef HAVE_STDLIB_H
924: char *breakpoint;
925: #endif
926: #ifdef DEBUG_MEMORY
927: xmlGenericError(xmlGenericErrorContext,
928: "xmlInitMemory()\n");
929: #endif
930: /*
931: This is really not good code (see Bug 130419). Suggestions for
932: improvement will be welcome!
933: */
934: if (xmlMemInitialized) return(-1);
935: xmlMemInitialized = 1;
936: xmlMemMutex = xmlNewMutex();
937:
938: #ifdef HAVE_STDLIB_H
939: breakpoint = getenv("XML_MEM_BREAKPOINT");
940: if (breakpoint != NULL) {
941: sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
942: }
943: #endif
944: #ifdef HAVE_STDLIB_H
945: breakpoint = getenv("XML_MEM_TRACE");
946: if (breakpoint != NULL) {
947: sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
948: }
949: #endif
950:
951: #ifdef DEBUG_MEMORY
952: xmlGenericError(xmlGenericErrorContext,
953: "xmlInitMemory() Ok\n");
954: #endif
955: return(0);
956: }
957:
958: /**
959: * xmlCleanupMemory:
960: *
961: * Free up all the memory allocated by the library for its own
962: * use. This should not be called by user level code.
963: */
964: void
965: xmlCleanupMemory(void) {
966: #ifdef DEBUG_MEMORY
967: xmlGenericError(xmlGenericErrorContext,
968: "xmlCleanupMemory()\n");
969: #endif
970: if (xmlMemInitialized == 0)
971: return;
972:
973: xmlFreeMutex(xmlMemMutex);
974: xmlMemMutex = NULL;
975: xmlMemInitialized = 0;
976: #ifdef DEBUG_MEMORY
977: xmlGenericError(xmlGenericErrorContext,
978: "xmlCleanupMemory() Ok\n");
979: #endif
980: }
981:
982: /**
983: * xmlMemSetup:
984: * @freeFunc: the free() function to use
985: * @mallocFunc: the malloc() function to use
986: * @reallocFunc: the realloc() function to use
987: * @strdupFunc: the strdup() function to use
988: *
989: * Override the default memory access functions with a new set
990: * This has to be called before any other libxml routines !
991: *
992: * Should this be blocked if there was already some allocations
993: * done ?
994: *
995: * Returns 0 on success
996: */
997: int
998: xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
999: xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
1000: #ifdef DEBUG_MEMORY
1001: xmlGenericError(xmlGenericErrorContext,
1002: "xmlMemSetup()\n");
1003: #endif
1004: if (freeFunc == NULL)
1005: return(-1);
1006: if (mallocFunc == NULL)
1007: return(-1);
1008: if (reallocFunc == NULL)
1009: return(-1);
1010: if (strdupFunc == NULL)
1011: return(-1);
1012: xmlFree = freeFunc;
1013: xmlMalloc = mallocFunc;
1014: xmlMallocAtomic = mallocFunc;
1015: xmlRealloc = reallocFunc;
1016: xmlMemStrdup = strdupFunc;
1017: #ifdef DEBUG_MEMORY
1018: xmlGenericError(xmlGenericErrorContext,
1019: "xmlMemSetup() Ok\n");
1020: #endif
1021: return(0);
1022: }
1023:
1024: /**
1025: * xmlMemGet:
1026: * @freeFunc: place to save the free() function in use
1027: * @mallocFunc: place to save the malloc() function in use
1028: * @reallocFunc: place to save the realloc() function in use
1029: * @strdupFunc: place to save the strdup() function in use
1030: *
1031: * Provides the memory access functions set currently in use
1032: *
1033: * Returns 0 on success
1034: */
1035: int
1036: xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1037: xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
1038: if (freeFunc != NULL) *freeFunc = xmlFree;
1039: if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1040: if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1041: if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1042: return(0);
1043: }
1044:
1045: /**
1046: * xmlGcMemSetup:
1047: * @freeFunc: the free() function to use
1048: * @mallocFunc: the malloc() function to use
1049: * @mallocAtomicFunc: the malloc() function to use for atomic allocations
1050: * @reallocFunc: the realloc() function to use
1051: * @strdupFunc: the strdup() function to use
1052: *
1053: * Override the default memory access functions with a new set
1054: * This has to be called before any other libxml routines !
1055: * The mallocAtomicFunc is specialized for atomic block
1056: * allocations (i.e. of areas useful for garbage collected memory allocators
1057: *
1058: * Should this be blocked if there was already some allocations
1059: * done ?
1060: *
1061: * Returns 0 on success
1062: */
1063: int
1064: xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
1065: xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
1066: xmlStrdupFunc strdupFunc) {
1067: #ifdef DEBUG_MEMORY
1068: xmlGenericError(xmlGenericErrorContext,
1069: "xmlGcMemSetup()\n");
1070: #endif
1071: if (freeFunc == NULL)
1072: return(-1);
1073: if (mallocFunc == NULL)
1074: return(-1);
1075: if (mallocAtomicFunc == NULL)
1076: return(-1);
1077: if (reallocFunc == NULL)
1078: return(-1);
1079: if (strdupFunc == NULL)
1080: return(-1);
1081: xmlFree = freeFunc;
1082: xmlMalloc = mallocFunc;
1083: xmlMallocAtomic = mallocAtomicFunc;
1084: xmlRealloc = reallocFunc;
1085: xmlMemStrdup = strdupFunc;
1086: #ifdef DEBUG_MEMORY
1087: xmlGenericError(xmlGenericErrorContext,
1088: "xmlGcMemSetup() Ok\n");
1089: #endif
1090: return(0);
1091: }
1092:
1093: /**
1094: * xmlGcMemGet:
1095: * @freeFunc: place to save the free() function in use
1096: * @mallocFunc: place to save the malloc() function in use
1097: * @mallocAtomicFunc: place to save the atomic malloc() function in use
1098: * @reallocFunc: place to save the realloc() function in use
1099: * @strdupFunc: place to save the strdup() function in use
1100: *
1101: * Provides the memory access functions set currently in use
1102: * The mallocAtomicFunc is specialized for atomic block
1103: * allocations (i.e. of areas useful for garbage collected memory allocators
1104: *
1105: * Returns 0 on success
1106: */
1107: int
1108: xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
1109: xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
1110: xmlStrdupFunc *strdupFunc) {
1111: if (freeFunc != NULL) *freeFunc = xmlFree;
1112: if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
1113: if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
1114: if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
1115: if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1116: return(0);
1117: }
1118:
1119: #define bottom_xmlmemory
1120: #include "elfgcchack.h"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>