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