Annotation of XML/xmlmemory.c, revision 1.7
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
8: #define HAVE_FCNTL_H
9: #include <io.h>
10: #else
1.4 daniel 11: #include "config.h"
1.3 daniel 12: #endif
13:
14: #include <stdio.h>
15: #include <string.h>
16:
17: #ifdef HAVE_SYS_TYPES_H
1.1 daniel 18: #include <sys/types.h>
1.3 daniel 19: #endif
1.4 daniel 20: #ifdef HAVE_TIME_H
21: #include <time.h>
22: #endif
1.3 daniel 23: #ifdef HAVE_MALLOC_H
1.1 daniel 24: #include <malloc.h>
1.3 daniel 25: #endif
1.7 ! daniel 26: #ifdef HAVE_STDLIB_H
! 27: #include <stdlib.h>
! 28: #endif
! 29:
1.3 daniel 30:
1.1 daniel 31: #include "xmlmemory.h"
32:
1.2 daniel 33: #ifndef NO_DEBUG_MEMORY
1.1 daniel 34: #ifdef xmlMalloc
35: #undef xmlMalloc
36: #endif
37: #ifdef xmlRealloc
38: #undef xmlRealloc
39: #endif
40: #ifdef xmlMemStrdup
41: #undef xmlMemStrdup
42: #endif
1.6 daniel 43:
1.1 daniel 44: extern void xmlMemoryDump(void);
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.7 ! daniel 121: @file: 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.4 daniel 143: fprintf(stderr, "xmlMalloc : Out of free space\n");
144: xmlMemoryDump();
1.1 daniel 145: }
146: p->mh_tag = MEMTAG;
147: p->mh_number = ++block;
148: p->mh_size = size;
149: p->mh_type = MALLOC_TYPE;
150: p->mh_file = file;
151: p->mh_line = line;
152: debugMemSize += size;
1.7 ! daniel 153: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
1.1 daniel 154: #ifdef MEM_LIST
155: debugmem_list_add(p);
156: #endif
157:
158: #ifdef DEBUG_MEMORY
159: fprintf(stderr, "Malloc(%d) Ok\n",size);
160: #endif
161:
1.7 ! daniel 162: if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
1.1 daniel 163:
164: TEST_POINT
165:
166: return(HDR_2_CLIENT(p));
167: }
168:
169: /**
170: * xmlMalloc:
171: * @size: an int specifying the size in byte to allocate.
172: *
173: * a malloc() equivalent, with logging of the allocation info.
174: *
175: * Returns a pointer to the allocated area or NULL in case of lack of memory.
176: */
177:
178: void *
179: xmlMalloc(int size)
180: {
181: return(xmlMallocLoc(size, "none", 0));
182: }
183:
184: /**
185: * xmlReallocLoc:
186: * @ptr: the initial memory block pointer
187: * @size: an int specifying the size in byte to allocate.
188: * @file: the file name or NULL
189: * @file: the line number
190: *
191: * a realloc() equivalent, with logging of the allocation info.
192: *
193: * Returns a pointer to the allocated area or NULL in case of lack of memory.
194: */
195:
196: void *
197: xmlReallocLoc(void *ptr,int size, const char * file, int line)
198: {
199: MEMHDR *p;
200: unsigned long number;
201:
1.7 ! daniel 202: if (!xmlMemInitialized) xmlInitMemory();
1.1 daniel 203: TEST_POINT
204:
205: p = CLIENT_2_HDR(ptr);
206: number = p->mh_number;
207: if (p->mh_tag != MEMTAG) {
1.4 daniel 208: Mem_Tag_Err(p);
1.1 daniel 209: goto error;
210: }
211: p->mh_tag = ~MEMTAG;
212: debugMemSize -= p->mh_size;
213: #ifdef MEM_LIST
214: debugmem_list_delete(p);
215: #endif
216:
217: p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
218: if (!p) {
219: goto error;
220: }
221: p->mh_tag = MEMTAG;
222: p->mh_number = number;
223: p->mh_type = REALLOC_TYPE;
224: p->mh_size = size;
225: p->mh_file = file;
226: p->mh_line = line;
227: debugMemSize += size;
1.7 ! daniel 228: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
1.1 daniel 229: #ifdef MEM_LIST
230: debugmem_list_add(p);
231: #endif
232:
233: TEST_POINT
234:
235: return(HDR_2_CLIENT(p));
236:
237: error:
238: return(NULL);
239: }
240:
241: /**
242: * xmlRealloc:
243: * @ptr: the initial memory block pointer
244: * @size: an int specifying the size in byte to allocate.
245: *
246: * a realloc() equivalent, with logging of the allocation info.
247: *
248: * Returns a pointer to the allocated area or NULL in case of lack of memory.
249: */
250:
251: void *
252: xmlRealloc(void *ptr,int size) {
253: return(xmlReallocLoc(ptr, size, "none", 0));
254: }
255:
256: /**
257: * xmlFree:
258: * @ptr: the memory block pointer
259: *
260: * a free() equivalent, with error checking.
261: */
262: void
263: xmlFree(void *ptr)
264: {
265: MEMHDR *p;
266:
267: TEST_POINT
268:
269: p = CLIENT_2_HDR(ptr);
270: if (p->mh_tag != MEMTAG) {
1.4 daniel 271: Mem_Tag_Err(p);
272: goto error;
1.1 daniel 273: }
274: p->mh_tag = ~MEMTAG;
275: debugMemSize -= p->mh_size;
276:
277: #ifdef MEM_LIST
278: debugmem_list_delete(p);
279: #endif
280: free(p);
281:
282: TEST_POINT
283:
284: return;
285:
286: error:
287: fprintf(stderr, "xmlFree(%X) error\n", (unsigned int) ptr);
288: return;
289: }
290:
291: /**
292: * xmlMemStrdupLoc:
293: * @ptr: the initial string pointer
294: * @file: the file name or NULL
295: * @file: the line number
296: *
297: * a strdup() equivalent, with logging of the allocation info.
298: *
299: * Returns a pointer to the new string or NULL if allocation error occured.
300: */
301:
302: char *
303: xmlMemStrdupLoc(const char *str, const char *file, int line)
304: {
305: char *s;
306: size_t size = strlen(str) + 1;
307: MEMHDR *p;
308:
1.7 ! daniel 309: if (!xmlMemInitialized) xmlInitMemory();
1.1 daniel 310: TEST_POINT
311:
312: p = (MEMHDR *) malloc(RESERVE_SIZE+size);
313: if (!p) {
1.4 daniel 314: goto error;
1.1 daniel 315: }
316: p->mh_tag = MEMTAG;
317: p->mh_number = ++block;
318: p->mh_size = size;
319: p->mh_type = STRDUP_TYPE;
320: p->mh_file = file;
321: p->mh_line = line;
322: debugMemSize += size;
1.7 ! daniel 323: if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
1.1 daniel 324: #ifdef MEM_LIST
325: debugmem_list_add(p);
326: #endif
327: s = HDR_2_CLIENT(p);
328:
1.7 ! daniel 329: if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
! 330:
1.1 daniel 331: if (s != NULL)
1.4 daniel 332: strcpy(s,str);
1.1 daniel 333: else
1.4 daniel 334: goto error;
1.1 daniel 335:
336: TEST_POINT
337:
338: return(s);
339:
340: error:
341: return(NULL);
342: }
343:
344: /**
345: * xmlMemStrdup:
346: * @ptr: the initial string pointer
347: *
348: * a strdup() equivalent, with logging of the allocation info.
349: *
350: * Returns a pointer to the new string or NULL if allocation error occured.
351: */
352:
353: char *
354: xmlMemStrdup(const char *str) {
355: return(xmlMemStrdupLoc(str, "none", 0));
356: }
357:
358: /**
359: * xmlMemUsed:
360: *
361: * returns the amount of memory currenly allocated
362: *
363: * Returns an int representing the amount of memory allocated.
364: */
365:
366: int
367: xmlMemUsed(void) {
368: return(debugMemSize);
369: }
370:
371: /**
372: * xmlMemDisplay:
373: * @fp: a FILE descriptor used as the output file, if NULL, the result is
374: 8 written to the file .memorylist
375: *
376: * show in-extenso the memory blocks allocated
377: */
378:
379: void
380: xmlMemDisplay(FILE *fp)
381: {
382: #ifdef MEM_LIST
1.4 daniel 383: MEMHDR *p;
384: int idx;
385: #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
1.5 daniel 386: time_t currentTime;
1.4 daniel 387: char buf[500];
388: struct tm * tstruct;
389:
1.5 daniel 390: currentTime = time(NULL);
391: tstruct = localtime(¤tTime);
1.4 daniel 392: strftime(buf, sizeof(buf) - 1, "%c", tstruct);
393: fprintf(fp," %s\n\n", buf);
394: #endif
395:
1.1 daniel 396:
1.7 ! daniel 397: fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
! 398: debugMemSize, debugMaxMemSize);
1.4 daniel 399: fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
400: idx = 0;
401: p = memlist;
402: while (p) {
1.1 daniel 403: fprintf(fp,"%-5u %6lu %6u ",idx++,p->mh_number,p->mh_size);
1.4 daniel 404: switch (p->mh_type) {
405: case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
406: case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
407: case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
408: default:fprintf(fp," ??? in ");break;
409: }
1.1 daniel 410: if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
1.4 daniel 411: if (p->mh_tag != MEMTAG)
1.1 daniel 412: fprintf(fp," INVALID");
1.4 daniel 413: fprintf(fp,"\n");
414: p = p->mh_next;
415: }
1.1 daniel 416: #else
1.4 daniel 417: fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
1.1 daniel 418: #endif
419: }
420:
421: #ifdef MEM_LIST
422:
423: void debugmem_list_add(MEMHDR *p)
424: {
1.4 daniel 425: p->mh_next = memlist;
426: p->mh_prev = NULL;
427: if (memlist) memlist->mh_prev = p;
428: memlist = p;
1.1 daniel 429: #ifdef MEM_LIST_DEBUG
1.4 daniel 430: if (stderr)
431: Mem_Display(stderr);
1.1 daniel 432: #endif
433: }
434:
435: void debugmem_list_delete(MEMHDR *p)
436: {
1.4 daniel 437: if (p->mh_next)
438: p->mh_next->mh_prev = p->mh_prev;
439: if (p->mh_prev)
440: p->mh_prev->mh_next = p->mh_next;
441: else memlist = p->mh_next;
1.1 daniel 442: #ifdef MEM_LIST_DEBUG
1.4 daniel 443: if (stderr)
444: Mem_Display(stderr);
1.1 daniel 445: #endif
446: }
447:
448: #endif
449:
450: /*
451: * debugmem_tag_error : internal error function.
452: */
453:
454: void debugmem_tag_error(void *p)
455: {
1.4 daniel 456: fprintf(stderr, "Memory tag error occurs :%p \n\t bye\n", p);
1.1 daniel 457: #ifdef MEM_LIST
1.4 daniel 458: if (stderr)
459: xmlMemDisplay(stderr);
1.1 daniel 460: #endif
461: }
462:
463: FILE *xmlMemoryDumpFile = NULL;
464:
465:
466: /**
467: * xmlMemoryDump:
468: *
469: * Dump in-extenso the memory blocks allocated to the file .memorylist
470: */
471:
472: void
473: xmlMemoryDump(void)
474: {
475: FILE *dump;
476:
477: dump = fopen(".memdump", "w");
478: if (dump == NULL) xmlMemoryDumpFile = stdout;
479: else xmlMemoryDumpFile = dump;
480:
481: xmlMemDisplay(xmlMemoryDumpFile);
482:
483: if (dump != NULL) fclose(dump);
484: }
485:
486:
487: /****************************************************************
488: * *
489: * Initialization Routines *
490: * *
491: ****************************************************************/
492:
493: /**
494: * xmlInitMemory:
495: *
496: * Initialize the memory layer.
1.6 daniel 497: *
498: * Returns 0 on success
1.1 daniel 499: */
500:
501:
502: int
503: xmlInitMemory(void)
504: {
505: int ret;
1.7 ! daniel 506:
! 507: #ifdef HAVE_STDLIB_H
! 508: char *breakpoint;
! 509:
! 510: breakpoint = getenv("XML_MEM_BREAKPOINT");
! 511: if (breakpoint != NULL) {
! 512: sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
! 513: }
! 514: #endif
1.1 daniel 515:
516: #ifdef DEBUG_MEMORY
517: fprintf(stderr, "xmlInitMemory() Ok\n");
518: #endif
519: ret = 0;
520: return(ret);
521: }
522:
1.2 daniel 523: #endif /* ! NO_DEBUG_MEMORY */
Webmaster