Annotation of XML/xmlmemory.c, revision 1.16
1.1 daniel 1: /*
2: * memory.c: libxml memory allocator wrapper.
3: *
4: * Daniel.Veillard@w3.org
5: */
6:
1.3 daniel 7: #ifdef WIN32
1.9 daniel 8: #include "win32config.h"
1.3 daniel 9: #else
1.4 daniel 10: #include "config.h"
1.3 daniel 11: #endif
12:
13: #include <stdio.h>
14: #include <string.h>
15:
16: #ifdef HAVE_SYS_TYPES_H
1.1 daniel 17: #include <sys/types.h>
1.3 daniel 18: #endif
1.4 daniel 19: #ifdef HAVE_TIME_H
20: #include <time.h>
21: #endif
1.3 daniel 22: #ifdef HAVE_MALLOC_H
1.1 daniel 23: #include <malloc.h>
1.3 daniel 24: #endif
1.7 daniel 25: #ifdef HAVE_STDLIB_H
26: #include <stdlib.h>
27: #endif
1.11 daniel 28: #ifdef HAVE_CTYPE_H
29: #include <ctype.h>
30: #endif
1.7 daniel 31:
1.3 daniel 32:
1.14 daniel 33: #include <libxml/xmlmemory.h>
1.1 daniel 34:
35: #ifdef xmlMalloc
36: #undef xmlMalloc
37: #endif
38: #ifdef xmlRealloc
39: #undef xmlRealloc
40: #endif
41: #ifdef xmlMemStrdup
42: #undef xmlMemStrdup
43: #endif
1.6 daniel 44:
1.1 daniel 45:
46: /*
47: * Each of the blocks allocated begin with a header containing informations
48: */
49:
50: #define MEMTAG 0x5aa5
51:
52: #define MALLOC_TYPE 1
53: #define REALLOC_TYPE 2
54: #define STRDUP_TYPE 3
55:
56: typedef struct memnod {
57: unsigned int mh_tag;
58: unsigned int mh_type;
59: unsigned long mh_number;
60: size_t mh_size;
61: #ifdef MEM_LIST
62: struct memnod *mh_next;
63: struct memnod *mh_prev;
64: #endif
65: const char *mh_file;
66: unsigned int mh_line;
67: } MEMHDR;
68:
69:
70: #ifdef SUN4
71: #define ALIGN_SIZE 16
72: #else
73: #define ALIGN_SIZE sizeof(double)
74: #endif
75: #define HDR_SIZE sizeof(MEMHDR)
76: #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
77: / ALIGN_SIZE ) * ALIGN_SIZE)
78:
79:
80: #define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
81: #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
82:
83:
84: static unsigned long debugMemSize = 0;
1.7 daniel 85: static unsigned long debugMaxMemSize = 0;
1.1 daniel 86: static int block=0;
1.7 daniel 87: int xmlMemStopAtBlock = 0;
88: int xmlMemInitialized = 0;
1.1 daniel 89: #ifdef MEM_LIST
90: static MEMHDR *memlist = NULL;
91: #endif
92:
93: void debugmem_tag_error(void *addr);
94: #ifdef MEM_LIST
95: void debugmem_list_add(MEMHDR *);
96: void debugmem_list_delete(MEMHDR *);
97: #endif
98: #define Mem_Tag_Err(a) debugmem_tag_error(a);
99:
100: #ifndef TEST_POINT
101: #define TEST_POINT
102: #endif
103:
104: /**
1.7 daniel 105: * xmlMallocBreakpoint:
106: *
107: * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
108: * number reaches the specified value this function is called. One need to add a breakpoint
109: * to it to get the context in which the given block is allocated.
110: */
111:
112: void
113: xmlMallocBreakpoint(void) {
114: fprintf(stderr, "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
115: }
116:
117: /**
1.1 daniel 118: * xmlMallocLoc:
119: * @size: an int specifying the size in byte to allocate.
120: * @file: the file name or NULL
1.15 daniel 121: * @line: the line number
1.1 daniel 122: *
123: * a malloc() equivalent, with logging of the allocation info.
124: *
125: * Returns a pointer to the allocated area or NULL in case of lack of memory.
126: */
127:
128: void *
129: xmlMallocLoc(int size, const char * file, int line)
130: {
131: MEMHDR *p;
132:
1.7 daniel 133: if (!xmlMemInitialized) xmlInitMemory();
1.1 daniel 134: #ifdef DEBUG_MEMORY
135: fprintf(stderr, "Malloc(%d)\n",size);
136: #endif
137:
138: TEST_POINT
139:
140: p = (MEMHDR *) malloc(RESERVE_SIZE+size);
141:
142: if (!p) {
1.8 daniel 143: fprintf(stderr, "xmlMalloc : Out of free space\n");
144: xmlMemoryDump();
145: return(NULL);
1.1 daniel 146: }
147: p->mh_tag = MEMTAG;
148: p->mh_number = ++block;
149: p->mh_size = size;
150: p->mh_type = MALLOC_TYPE;
151: p->mh_file = file;
152: p->mh_line = line;
153: debugMemSize += size;
1.7 daniel 154: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
1.1 daniel 155: #ifdef MEM_LIST
156: debugmem_list_add(p);
157: #endif
158:
159: #ifdef DEBUG_MEMORY
160: fprintf(stderr, "Malloc(%d) Ok\n",size);
161: #endif
162:
1.7 daniel 163: if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
1.1 daniel 164:
165: TEST_POINT
166:
167: return(HDR_2_CLIENT(p));
168: }
169:
170: /**
1.12 daniel 171: * xmlMemMalloc:
1.1 daniel 172: * @size: an int specifying the size in byte to allocate.
173: *
174: * a malloc() equivalent, with logging of the allocation info.
175: *
176: * Returns a pointer to the allocated area or NULL in case of lack of memory.
177: */
178:
179: void *
1.12 daniel 180: xmlMemMalloc(int size)
1.1 daniel 181: {
182: return(xmlMallocLoc(size, "none", 0));
183: }
184:
185: /**
186: * xmlReallocLoc:
187: * @ptr: the initial memory block pointer
188: * @size: an int specifying the size in byte to allocate.
189: * @file: the file name or NULL
1.15 daniel 190: * @line: the line number
1.1 daniel 191: *
192: * a realloc() equivalent, with logging of the allocation info.
193: *
194: * Returns a pointer to the allocated area or NULL in case of lack of memory.
195: */
196:
197: void *
198: xmlReallocLoc(void *ptr,int size, const char * file, int line)
199: {
200: MEMHDR *p;
201: unsigned long number;
202:
1.7 daniel 203: if (!xmlMemInitialized) xmlInitMemory();
1.1 daniel 204: TEST_POINT
205:
206: p = CLIENT_2_HDR(ptr);
207: number = p->mh_number;
208: if (p->mh_tag != MEMTAG) {
1.4 daniel 209: Mem_Tag_Err(p);
1.1 daniel 210: goto error;
211: }
212: p->mh_tag = ~MEMTAG;
213: debugMemSize -= p->mh_size;
214: #ifdef MEM_LIST
215: debugmem_list_delete(p);
216: #endif
217:
218: p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
219: if (!p) {
220: goto error;
221: }
222: p->mh_tag = MEMTAG;
223: p->mh_number = number;
224: p->mh_type = REALLOC_TYPE;
225: p->mh_size = size;
226: p->mh_file = file;
227: p->mh_line = line;
228: debugMemSize += size;
1.7 daniel 229: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
1.1 daniel 230: #ifdef MEM_LIST
231: debugmem_list_add(p);
232: #endif
233:
234: TEST_POINT
235:
236: return(HDR_2_CLIENT(p));
237:
238: error:
239: return(NULL);
240: }
241:
242: /**
1.12 daniel 243: * xmlMemRealloc:
1.1 daniel 244: * @ptr: the initial memory block pointer
245: * @size: an int specifying the size in byte to allocate.
246: *
247: * a realloc() equivalent, with logging of the allocation info.
248: *
249: * Returns a pointer to the allocated area or NULL in case of lack of memory.
250: */
251:
252: void *
1.12 daniel 253: xmlMemRealloc(void *ptr,int size) {
1.1 daniel 254: return(xmlReallocLoc(ptr, size, "none", 0));
255: }
256:
257: /**
1.12 daniel 258: * xmlMemFree:
1.1 daniel 259: * @ptr: the memory block pointer
260: *
261: * a free() equivalent, with error checking.
262: */
263: void
1.12 daniel 264: xmlMemFree(void *ptr)
1.1 daniel 265: {
266: MEMHDR *p;
267:
268: TEST_POINT
269:
270: p = CLIENT_2_HDR(ptr);
271: if (p->mh_tag != MEMTAG) {
1.4 daniel 272: Mem_Tag_Err(p);
273: goto error;
1.1 daniel 274: }
275: p->mh_tag = ~MEMTAG;
276: debugMemSize -= p->mh_size;
277:
278: #ifdef MEM_LIST
279: debugmem_list_delete(p);
280: #endif
281: free(p);
282:
283: TEST_POINT
284:
285: return;
286:
287: error:
288: fprintf(stderr, "xmlFree(%X) error\n", (unsigned int) ptr);
289: return;
290: }
291:
292: /**
293: * xmlMemStrdupLoc:
294: * @ptr: the initial string pointer
295: * @file: the file name or NULL
1.15 daniel 296: * @line: the line number
1.1 daniel 297: *
298: * a strdup() equivalent, with logging of the allocation info.
299: *
300: * Returns a pointer to the new string or NULL if allocation error occured.
301: */
302:
303: char *
304: xmlMemStrdupLoc(const char *str, const char *file, int line)
305: {
306: char *s;
307: size_t size = strlen(str) + 1;
308: MEMHDR *p;
309:
1.7 daniel 310: if (!xmlMemInitialized) xmlInitMemory();
1.1 daniel 311: TEST_POINT
312:
313: p = (MEMHDR *) malloc(RESERVE_SIZE+size);
314: if (!p) {
1.4 daniel 315: goto error;
1.1 daniel 316: }
317: p->mh_tag = MEMTAG;
318: p->mh_number = ++block;
319: p->mh_size = size;
320: p->mh_type = STRDUP_TYPE;
321: p->mh_file = file;
322: p->mh_line = line;
323: debugMemSize += size;
1.7 daniel 324: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
1.1 daniel 325: #ifdef MEM_LIST
326: debugmem_list_add(p);
327: #endif
1.16 ! veillard 328: s = (char *) HDR_2_CLIENT(p);
1.1 daniel 329:
1.7 daniel 330: if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
331:
1.1 daniel 332: if (s != NULL)
1.4 daniel 333: strcpy(s,str);
1.1 daniel 334: else
1.4 daniel 335: goto error;
1.1 daniel 336:
337: TEST_POINT
338:
339: return(s);
340:
341: error:
342: return(NULL);
343: }
344:
345: /**
1.12 daniel 346: * xmlMemoryStrdup:
1.1 daniel 347: * @ptr: the initial string pointer
348: *
349: * a strdup() equivalent, with logging of the allocation info.
350: *
351: * Returns a pointer to the new string or NULL if allocation error occured.
352: */
353:
354: char *
1.12 daniel 355: xmlMemoryStrdup(const char *str) {
1.1 daniel 356: return(xmlMemStrdupLoc(str, "none", 0));
357: }
358:
359: /**
360: * xmlMemUsed:
361: *
362: * returns the amount of memory currenly allocated
363: *
364: * Returns an int representing the amount of memory allocated.
365: */
366:
367: int
368: xmlMemUsed(void) {
369: return(debugMemSize);
370: }
371:
1.11 daniel 372: #ifdef MEM_LIST
373: /**
374: * xmlMemContentShow:
375: * @fp: a FILE descriptor used as the output file
376: * @p: a memory block header
377: *
378: * tries to show some content from the memory block
379: */
380:
381: void
382: xmlMemContentShow(FILE *fp, MEMHDR *p)
383: {
384: int i,j,len = p->mh_size;
1.16 ! veillard 385: const char *buf = (const char *) HDR_2_CLIENT(p);
1.11 daniel 386:
387: for (i = 0;i < len;i++) {
388: if (buf[i] == 0) break;
389: if (!isprint(buf[i])) break;
390: }
391: if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
392: if (len >= 4) {
393: MEMHDR *q;
394: void *cur;
395:
396: for (j = 0;j < len -3;j += 4) {
397: cur = *((void **) &buf[j]);
398: q = CLIENT_2_HDR(cur);
399: p = memlist;
400: while (p != NULL) {
401: if (p == q) break;
402: p = p->mh_next;
403: }
404: if (p == q) {
405: fprintf(fp, " pointer to #%lu at index %d",
406: p->mh_number, j);
407: return;
408: }
409: }
410: }
411: } else if ((i == 0) && (buf[i] == 0)) {
412: fprintf(fp," null");
413: } else {
414: if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
415: else {
416: fprintf(fp," [");
417: for (j = 0;j < i;j++)
418: fprintf(fp,"%c", buf[j]);
419: fprintf(fp,"]");
420: }
421: }
422: }
423: #endif
424:
1.1 daniel 425: /**
1.10 daniel 426: * xmlMemShow:
427: * @fp: a FILE descriptor used as the output file
428: * @nr: number of entries to dump
429: *
430: * show a show display of the memory allocated, and dump
431: * the @nr last allocated areas which were not freed
432: */
433:
434: void
435: xmlMemShow(FILE *fp, int nr)
436: {
437: #ifdef MEM_LIST
438: MEMHDR *p;
439: #endif
440:
441: if (fp != NULL)
442: fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
443: debugMemSize, debugMaxMemSize);
444: #ifdef MEM_LIST
445: if (nr > 0) {
446: fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
447: p = memlist;
448: while ((p) && nr > 0) {
449: fprintf(fp,"%6lu %6u ",p->mh_number,p->mh_size);
450: switch (p->mh_type) {
451: case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
452: case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
453: case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
454: default:fprintf(fp," ??? in ");break;
455: }
456: if (p->mh_file != NULL)
457: fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
458: if (p->mh_tag != MEMTAG)
459: fprintf(fp," INVALID");
1.11 daniel 460: xmlMemContentShow(fp, p);
1.10 daniel 461: fprintf(fp,"\n");
462: nr--;
463: p = p->mh_next;
464: }
465: }
466: #endif /* MEM_LIST */
467: }
468:
469: /**
1.1 daniel 470: * xmlMemDisplay:
471: * @fp: a FILE descriptor used as the output file, if NULL, the result is
1.10 daniel 472: * written to the file .memorylist
1.1 daniel 473: *
474: * show in-extenso the memory blocks allocated
475: */
476:
477: void
478: xmlMemDisplay(FILE *fp)
479: {
480: #ifdef MEM_LIST
1.4 daniel 481: MEMHDR *p;
482: int idx;
483: #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
1.5 daniel 484: time_t currentTime;
1.4 daniel 485: char buf[500];
486: struct tm * tstruct;
487:
1.5 daniel 488: currentTime = time(NULL);
489: tstruct = localtime(¤tTime);
1.4 daniel 490: strftime(buf, sizeof(buf) - 1, "%c", tstruct);
491: fprintf(fp," %s\n\n", buf);
492: #endif
493:
1.1 daniel 494:
1.7 daniel 495: fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
496: debugMemSize, debugMaxMemSize);
1.4 daniel 497: fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
498: idx = 0;
499: p = memlist;
500: while (p) {
1.1 daniel 501: fprintf(fp,"%-5u %6lu %6u ",idx++,p->mh_number,p->mh_size);
1.4 daniel 502: switch (p->mh_type) {
503: case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
504: case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
505: case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
506: default:fprintf(fp," ??? in ");break;
507: }
1.1 daniel 508: if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
1.4 daniel 509: if (p->mh_tag != MEMTAG)
1.1 daniel 510: fprintf(fp," INVALID");
1.11 daniel 511: xmlMemContentShow(fp, p);
1.4 daniel 512: fprintf(fp,"\n");
513: p = p->mh_next;
514: }
1.1 daniel 515: #else
1.4 daniel 516: fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
1.1 daniel 517: #endif
518: }
519:
520: #ifdef MEM_LIST
521:
522: void debugmem_list_add(MEMHDR *p)
523: {
1.4 daniel 524: p->mh_next = memlist;
525: p->mh_prev = NULL;
526: if (memlist) memlist->mh_prev = p;
527: memlist = p;
1.1 daniel 528: #ifdef MEM_LIST_DEBUG
1.4 daniel 529: if (stderr)
530: Mem_Display(stderr);
1.1 daniel 531: #endif
532: }
533:
534: void debugmem_list_delete(MEMHDR *p)
535: {
1.4 daniel 536: if (p->mh_next)
537: p->mh_next->mh_prev = p->mh_prev;
538: if (p->mh_prev)
539: p->mh_prev->mh_next = p->mh_next;
540: else memlist = p->mh_next;
1.1 daniel 541: #ifdef MEM_LIST_DEBUG
1.4 daniel 542: if (stderr)
543: Mem_Display(stderr);
1.1 daniel 544: #endif
545: }
546:
547: #endif
548:
549: /*
550: * debugmem_tag_error : internal error function.
551: */
552:
553: void debugmem_tag_error(void *p)
554: {
1.4 daniel 555: fprintf(stderr, "Memory tag error occurs :%p \n\t bye\n", p);
1.1 daniel 556: #ifdef MEM_LIST
1.4 daniel 557: if (stderr)
558: xmlMemDisplay(stderr);
1.1 daniel 559: #endif
560: }
561:
562: FILE *xmlMemoryDumpFile = NULL;
563:
564:
565: /**
566: * xmlMemoryDump:
567: *
568: * Dump in-extenso the memory blocks allocated to the file .memorylist
569: */
570:
571: void
572: xmlMemoryDump(void)
573: {
1.13 daniel 574: #if defined(DEBUG_MEMORY_LOCATION) | defined(DEBUG_MEMORY)
1.1 daniel 575: FILE *dump;
576:
577: dump = fopen(".memdump", "w");
578: if (dump == NULL) xmlMemoryDumpFile = stdout;
579: else xmlMemoryDumpFile = dump;
580:
581: xmlMemDisplay(xmlMemoryDumpFile);
582:
583: if (dump != NULL) fclose(dump);
1.13 daniel 584: #endif
1.1 daniel 585: }
586:
587:
588: /****************************************************************
589: * *
590: * Initialization Routines *
591: * *
592: ****************************************************************/
593:
1.12 daniel 594: #if defined(DEBUG_MEMORY_LOCATION) | defined(DEBUG_MEMORY)
1.13 daniel 595: xmlFreeFunc xmlFree = (xmlFreeFunc) xmlMemFree;
596: xmlMallocFunc xmlMalloc = (xmlMallocFunc) xmlMemMalloc;
597: xmlReallocFunc xmlRealloc = (xmlReallocFunc) xmlMemRealloc;
598: xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) xmlMemoryStrdup;
1.12 daniel 599: #else
1.13 daniel 600: xmlFreeFunc xmlFree = (xmlFreeFunc) free;
601: xmlMallocFunc xmlMalloc = (xmlMallocFunc) malloc;
602: xmlReallocFunc xmlRealloc = (xmlReallocFunc) realloc;
603: xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) strdup;
1.12 daniel 604: #endif
605:
1.1 daniel 606: /**
607: * xmlInitMemory:
608: *
609: * Initialize the memory layer.
1.6 daniel 610: *
611: * Returns 0 on success
1.1 daniel 612: */
613:
1.12 daniel 614: static int xmlInitMemoryDone = 0;
1.1 daniel 615:
616: int
617: xmlInitMemory(void)
618: {
619: int ret;
1.7 daniel 620:
621: #ifdef HAVE_STDLIB_H
622: char *breakpoint;
1.12 daniel 623: #endif
624:
625: if (xmlInitMemoryDone) return(-1);
1.7 daniel 626:
1.12 daniel 627: #ifdef HAVE_STDLIB_H
1.7 daniel 628: breakpoint = getenv("XML_MEM_BREAKPOINT");
629: if (breakpoint != NULL) {
630: sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
631: }
632: #endif
1.1 daniel 633:
634: #ifdef DEBUG_MEMORY
635: fprintf(stderr, "xmlInitMemory() Ok\n");
636: #endif
637: ret = 0;
638: return(ret);
1.12 daniel 639: }
640:
641: /**
642: * xmlMemSetup:
643: * @freeFunc: the free() function to use
644: * @mallocFunc: the malloc() function to use
645: * @reallocFunc: the realloc() function to use
646: * @strdupFunc: the strdup() function to use
647: *
648: * Override the default memory access functions with a new set
1.13 daniel 649: * This has to be called before any other libxml routines !
650: *
651: * Should this be blocked if there was already some allocations
652: * done ?
1.12 daniel 653: *
654: * Returns 0 on success
655: */
656: int
657: xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
658: xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
659: if (freeFunc != NULL)
660: return(-1);
661: if (mallocFunc != NULL)
662: return(-1);
663: if (reallocFunc != NULL)
664: return(-1);
665: if (strdupFunc != NULL)
666: return(-1);
667: xmlFree = freeFunc;
668: xmlMalloc = mallocFunc;
669: xmlRealloc = reallocFunc;
670: xmlMemStrdup = strdupFunc;
671: return(0);
672: }
673:
674: /**
675: * xmlMemGet:
676: * @freeFunc: the free() function in use
677: * @mallocFunc: the malloc() function in use
678: * @reallocFunc: the realloc() function in use
679: * @strdupFunc: the strdup() function in use
680: *
681: * Return the memory access functions set currently in use
682: *
683: * Returns 0 on success
684: */
685: int
686: xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
687: xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
1.13 daniel 688: if (freeFunc != NULL) *freeFunc = xmlFree;
689: if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
690: if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
691: if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
1.12 daniel 692: return(0);
1.1 daniel 693: }
694:
Webmaster