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