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