Annotation of XML/xmlmemory.c, revision 1.8
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.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: /**
171: * xmlMalloc:
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 *
180: xmlMalloc(int size)
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
190: * @file: the line number
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: /**
243: * xmlRealloc:
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 *
253: xmlRealloc(void *ptr,int size) {
254: return(xmlReallocLoc(ptr, size, "none", 0));
255: }
256:
257: /**
258: * xmlFree:
259: * @ptr: the memory block pointer
260: *
261: * a free() equivalent, with error checking.
262: */
263: void
264: xmlFree(void *ptr)
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
296: * @file: the line number
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
328: s = HDR_2_CLIENT(p);
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: /**
346: * xmlMemStrdup:
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 *
355: xmlMemStrdup(const char *str) {
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:
372: /**
373: * xmlMemDisplay:
374: * @fp: a FILE descriptor used as the output file, if NULL, the result is
375: 8 written to the file .memorylist
376: *
377: * show in-extenso the memory blocks allocated
378: */
379:
380: void
381: xmlMemDisplay(FILE *fp)
382: {
383: #ifdef MEM_LIST
1.4 daniel 384: MEMHDR *p;
385: int idx;
386: #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
1.5 daniel 387: time_t currentTime;
1.4 daniel 388: char buf[500];
389: struct tm * tstruct;
390:
1.5 daniel 391: currentTime = time(NULL);
392: tstruct = localtime(¤tTime);
1.4 daniel 393: strftime(buf, sizeof(buf) - 1, "%c", tstruct);
394: fprintf(fp," %s\n\n", buf);
395: #endif
396:
1.1 daniel 397:
1.7 daniel 398: fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
399: debugMemSize, debugMaxMemSize);
1.4 daniel 400: fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
401: idx = 0;
402: p = memlist;
403: while (p) {
1.1 daniel 404: fprintf(fp,"%-5u %6lu %6u ",idx++,p->mh_number,p->mh_size);
1.4 daniel 405: switch (p->mh_type) {
406: case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
407: case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
408: case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
409: default:fprintf(fp," ??? in ");break;
410: }
1.1 daniel 411: if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
1.4 daniel 412: if (p->mh_tag != MEMTAG)
1.1 daniel 413: fprintf(fp," INVALID");
1.4 daniel 414: fprintf(fp,"\n");
415: p = p->mh_next;
416: }
1.1 daniel 417: #else
1.4 daniel 418: fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
1.1 daniel 419: #endif
420: }
421:
422: #ifdef MEM_LIST
423:
424: void debugmem_list_add(MEMHDR *p)
425: {
1.4 daniel 426: p->mh_next = memlist;
427: p->mh_prev = NULL;
428: if (memlist) memlist->mh_prev = p;
429: memlist = p;
1.1 daniel 430: #ifdef MEM_LIST_DEBUG
1.4 daniel 431: if (stderr)
432: Mem_Display(stderr);
1.1 daniel 433: #endif
434: }
435:
436: void debugmem_list_delete(MEMHDR *p)
437: {
1.4 daniel 438: if (p->mh_next)
439: p->mh_next->mh_prev = p->mh_prev;
440: if (p->mh_prev)
441: p->mh_prev->mh_next = p->mh_next;
442: else memlist = p->mh_next;
1.1 daniel 443: #ifdef MEM_LIST_DEBUG
1.4 daniel 444: if (stderr)
445: Mem_Display(stderr);
1.1 daniel 446: #endif
447: }
448:
449: #endif
450:
451: /*
452: * debugmem_tag_error : internal error function.
453: */
454:
455: void debugmem_tag_error(void *p)
456: {
1.4 daniel 457: fprintf(stderr, "Memory tag error occurs :%p \n\t bye\n", p);
1.1 daniel 458: #ifdef MEM_LIST
1.4 daniel 459: if (stderr)
460: xmlMemDisplay(stderr);
1.1 daniel 461: #endif
462: }
463:
464: FILE *xmlMemoryDumpFile = NULL;
465:
466:
467: /**
468: * xmlMemoryDump:
469: *
470: * Dump in-extenso the memory blocks allocated to the file .memorylist
471: */
472:
473: void
474: xmlMemoryDump(void)
475: {
476: FILE *dump;
477:
478: dump = fopen(".memdump", "w");
479: if (dump == NULL) xmlMemoryDumpFile = stdout;
480: else xmlMemoryDumpFile = dump;
481:
482: xmlMemDisplay(xmlMemoryDumpFile);
483:
484: if (dump != NULL) fclose(dump);
485: }
486:
487:
488: /****************************************************************
489: * *
490: * Initialization Routines *
491: * *
492: ****************************************************************/
493:
494: /**
495: * xmlInitMemory:
496: *
497: * Initialize the memory layer.
1.6 daniel 498: *
499: * Returns 0 on success
1.1 daniel 500: */
501:
502:
503: int
504: xmlInitMemory(void)
505: {
506: int ret;
1.7 daniel 507:
508: #ifdef HAVE_STDLIB_H
509: char *breakpoint;
510:
511: breakpoint = getenv("XML_MEM_BREAKPOINT");
512: if (breakpoint != NULL) {
513: sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
514: }
515: #endif
1.1 daniel 516:
517: #ifdef DEBUG_MEMORY
518: fprintf(stderr, "xmlInitMemory() Ok\n");
519: #endif
520: ret = 0;
521: return(ret);
522: }
523:
1.2 daniel 524: #endif /* ! NO_DEBUG_MEMORY */
Webmaster