|
|
1.1 daniel 1: /*
2: * memory.c: libxml memory allocator wrapper.
3: *
4: * Daniel.Veillard@w3.org
5: */
6:
7: #include <sys/types.h>
8: #include <string.h>
9: #include <stdio.h>
10: #include <malloc.h>
11: #include "xmlmemory.h"
12:
1.2 ! daniel 13: #ifndef NO_DEBUG_MEMORY
1.1 daniel 14:
15: #ifdef xmlMalloc
16: #undef xmlMalloc
17: #endif
18: #ifdef xmlRealloc
19: #undef xmlRealloc
20: #endif
21: #ifdef xmlMemStrdup
22: #undef xmlMemStrdup
23: #endif
24: extern void xmlMemoryDump(void);
25:
26: /*
27: * Each of the blocks allocated begin with a header containing informations
28: */
29:
30: #define MEMTAG 0x5aa5
31:
32: #define MALLOC_TYPE 1
33: #define REALLOC_TYPE 2
34: #define STRDUP_TYPE 3
35:
36: typedef struct memnod {
37: unsigned int mh_tag;
38: unsigned int mh_type;
39: unsigned long mh_number;
40: size_t mh_size;
41: #ifdef MEM_LIST
42: struct memnod *mh_next;
43: struct memnod *mh_prev;
44: #endif
45: const char *mh_file;
46: unsigned int mh_line;
47: } MEMHDR;
48:
49:
50: #ifdef SUN4
51: #define ALIGN_SIZE 16
52: #else
53: #define ALIGN_SIZE sizeof(double)
54: #endif
55: #define HDR_SIZE sizeof(MEMHDR)
56: #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
57: / ALIGN_SIZE ) * ALIGN_SIZE)
58:
59:
60: #define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
61: #define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
62:
63:
64: static unsigned long debugMemSize = 0;
65: static int block=0;
66: #ifdef MEM_LIST
67: static MEMHDR *memlist = NULL;
68: #endif
69:
70: void debugmem_tag_error(void *addr);
71: #ifdef MEM_LIST
72: void debugmem_list_add(MEMHDR *);
73: void debugmem_list_delete(MEMHDR *);
74: #endif
75: #define Mem_Tag_Err(a) debugmem_tag_error(a);
76:
77: #ifndef TEST_POINT
78: #define TEST_POINT
79: #endif
80:
81: /**
82: * xmlMallocLoc:
83: * @size: an int specifying the size in byte to allocate.
84: * @file: the file name or NULL
85: * @file: the line number
86: *
87: * a malloc() equivalent, with logging of the allocation info.
88: *
89: * Returns a pointer to the allocated area or NULL in case of lack of memory.
90: */
91:
92: void *
93: xmlMallocLoc(int size, const char * file, int line)
94: {
95: MEMHDR *p;
96:
97: #ifdef DEBUG_MEMORY
98: fprintf(stderr, "Malloc(%d)\n",size);
99: #endif
100:
101: TEST_POINT
102:
103: p = (MEMHDR *) malloc(RESERVE_SIZE+size);
104:
105: if (!p) {
106: fprintf(stderr, "xmlMalloc : Out of free space\n");
107: xmlMemoryDump();
108: }
109: p->mh_tag = MEMTAG;
110: p->mh_number = ++block;
111: p->mh_size = size;
112: p->mh_type = MALLOC_TYPE;
113: p->mh_file = file;
114: p->mh_line = line;
115: debugMemSize += size;
116: #ifdef MEM_LIST
117: debugmem_list_add(p);
118: #endif
119:
120: #ifdef DEBUG_MEMORY
121: fprintf(stderr, "Malloc(%d) Ok\n",size);
122: #endif
123:
124:
125: TEST_POINT
126:
127: return(HDR_2_CLIENT(p));
128: }
129:
130: /**
131: * xmlMalloc:
132: * @size: an int specifying the size in byte to allocate.
133: *
134: * a malloc() equivalent, with logging of the allocation info.
135: *
136: * Returns a pointer to the allocated area or NULL in case of lack of memory.
137: */
138:
139: void *
140: xmlMalloc(int size)
141: {
142: return(xmlMallocLoc(size, "none", 0));
143: }
144:
145: /**
146: * xmlReallocLoc:
147: * @ptr: the initial memory block pointer
148: * @size: an int specifying the size in byte to allocate.
149: * @file: the file name or NULL
150: * @file: the line number
151: *
152: * a realloc() equivalent, with logging of the allocation info.
153: *
154: * Returns a pointer to the allocated area or NULL in case of lack of memory.
155: */
156:
157: void *
158: xmlReallocLoc(void *ptr,int size, const char * file, int line)
159: {
160: MEMHDR *p;
161: unsigned long number;
162:
163: TEST_POINT
164:
165: p = CLIENT_2_HDR(ptr);
166: number = p->mh_number;
167: if (p->mh_tag != MEMTAG) {
168: Mem_Tag_Err(p);
169: goto error;
170: }
171: p->mh_tag = ~MEMTAG;
172: debugMemSize -= p->mh_size;
173: #ifdef MEM_LIST
174: debugmem_list_delete(p);
175: #endif
176:
177: p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
178: if (!p) {
179: goto error;
180: }
181: p->mh_tag = MEMTAG;
182: p->mh_number = number;
183: p->mh_type = REALLOC_TYPE;
184: p->mh_size = size;
185: p->mh_file = file;
186: p->mh_line = line;
187: debugMemSize += size;
188: #ifdef MEM_LIST
189: debugmem_list_add(p);
190: #endif
191:
192: TEST_POINT
193:
194: return(HDR_2_CLIENT(p));
195:
196: error:
197: return(NULL);
198: }
199:
200: /**
201: * xmlRealloc:
202: * @ptr: the initial memory block pointer
203: * @size: an int specifying the size in byte to allocate.
204: *
205: * a realloc() equivalent, with logging of the allocation info.
206: *
207: * Returns a pointer to the allocated area or NULL in case of lack of memory.
208: */
209:
210: void *
211: xmlRealloc(void *ptr,int size) {
212: return(xmlReallocLoc(ptr, size, "none", 0));
213: }
214:
215: /**
216: * xmlFree:
217: * @ptr: the memory block pointer
218: *
219: * a free() equivalent, with error checking.
220: *
221: * Returns a pointer to the allocated area or NULL in case of lack of memory.
222: */
223:
224:
225: void
226: xmlFree(void *ptr)
227: {
228: MEMHDR *p;
229:
230: TEST_POINT
231:
232: p = CLIENT_2_HDR(ptr);
233: if (p->mh_tag != MEMTAG) {
234: Mem_Tag_Err(p);
235: goto error;
236: }
237: p->mh_tag = ~MEMTAG;
238: debugMemSize -= p->mh_size;
239:
240: #ifdef MEM_LIST
241: debugmem_list_delete(p);
242: #endif
243: free(p);
244:
245: TEST_POINT
246:
247: return;
248:
249: error:
250: fprintf(stderr, "xmlFree(%X) error\n", (unsigned int) ptr);
251: return;
252: }
253:
254: /**
255: * xmlMemStrdupLoc:
256: * @ptr: the initial string pointer
257: * @file: the file name or NULL
258: * @file: the line number
259: *
260: * a strdup() equivalent, with logging of the allocation info.
261: *
262: * Returns a pointer to the new string or NULL if allocation error occured.
263: */
264:
265: char *
266: xmlMemStrdupLoc(const char *str, const char *file, int line)
267: {
268: char *s;
269: size_t size = strlen(str) + 1;
270: MEMHDR *p;
271:
272: TEST_POINT
273:
274: p = (MEMHDR *) malloc(RESERVE_SIZE+size);
275: if (!p) {
276: goto error;
277: }
278: p->mh_tag = MEMTAG;
279: p->mh_number = ++block;
280: p->mh_size = size;
281: p->mh_type = STRDUP_TYPE;
282: p->mh_file = file;
283: p->mh_line = line;
284: debugMemSize += size;
285: #ifdef MEM_LIST
286: debugmem_list_add(p);
287: #endif
288: s = HDR_2_CLIENT(p);
289:
290: if (s != NULL)
291: strcpy(s,str);
292: else
293: goto error;
294:
295: TEST_POINT
296:
297: return(s);
298:
299: error:
300: return(NULL);
301: }
302:
303: /**
304: * xmlMemStrdup:
305: * @ptr: the initial string pointer
306: *
307: * a strdup() equivalent, with logging of the allocation info.
308: *
309: * Returns a pointer to the new string or NULL if allocation error occured.
310: */
311:
312: char *
313: xmlMemStrdup(const char *str) {
314: return(xmlMemStrdupLoc(str, "none", 0));
315: }
316:
317: /**
318: * xmlMemUsed:
319: *
320: * returns the amount of memory currenly allocated
321: *
322: * Returns an int representing the amount of memory allocated.
323: */
324:
325: int
326: xmlMemUsed(void) {
327: return(debugMemSize);
328: }
329:
330: /**
331: * xmlMemDisplay:
332: * @fp: a FILE descriptor used as the output file, if NULL, the result is
333: 8 written to the file .memorylist
334: *
335: * show in-extenso the memory blocks allocated
336: */
337:
338: void
339: xmlMemDisplay(FILE *fp)
340: {
341: #ifdef MEM_LIST
342: MEMHDR *p;
343: int idx;
344:
345: fprintf(fp," MEMORY ALLOCATED : %lu\n",debugMemSize);
346: fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
347: idx = 0;
348: p = memlist;
349: while (p) {
350: fprintf(fp,"%-5u %6lu %6u ",idx++,p->mh_number,p->mh_size);
351: switch (p->mh_type) {
352: case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
353: case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
354: case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
355: default:fprintf(fp," ??? in ");break;
356: }
357: if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
358: if (p->mh_tag != MEMTAG)
359: fprintf(fp," INVALID");
360: fprintf(fp,"\n");
361: p = p->mh_next;
362: }
363: #else
364: fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
365: #endif
366: }
367:
368: #ifdef MEM_LIST
369:
370: void debugmem_list_add(MEMHDR *p)
371: {
372: p->mh_next = memlist;
373: p->mh_prev = NULL;
374: if (memlist) memlist->mh_prev = p;
375: memlist = p;
376: #ifdef MEM_LIST_DEBUG
377: if (stderr)
378: Mem_Display(stderr);
379: #endif
380: }
381:
382: void debugmem_list_delete(MEMHDR *p)
383: {
384: if (p->mh_next)
385: p->mh_next->mh_prev = p->mh_prev;
386: if (p->mh_prev)
387: p->mh_prev->mh_next = p->mh_next;
388: else memlist = p->mh_next;
389: #ifdef MEM_LIST_DEBUG
390: if (stderr)
391: Mem_Display(stderr);
392: #endif
393: }
394:
395: #endif
396:
397: /*
398: * debugmem_tag_error : internal error function.
399: */
400:
401: void debugmem_tag_error(void *p)
402: {
403: fprintf(stderr, "Memory tag error occurs :%p \n\t bye\n", p);
404: #ifdef MEM_LIST
405: if (stderr)
406: xmlMemDisplay(stderr);
407: #endif
408: }
409:
410: FILE *xmlMemoryDumpFile = NULL;
411:
412:
413: /**
414: * xmlMemoryDump:
415: *
416: * Dump in-extenso the memory blocks allocated to the file .memorylist
417: */
418:
419: void
420: xmlMemoryDump(void)
421: {
422: FILE *dump;
423:
424: dump = fopen(".memdump", "w");
425: if (dump == NULL) xmlMemoryDumpFile = stdout;
426: else xmlMemoryDumpFile = dump;
427:
428: xmlMemDisplay(xmlMemoryDumpFile);
429:
430: if (dump != NULL) fclose(dump);
431: }
432:
433:
434: /****************************************************************
435: * *
436: * Initialization Routines *
437: * *
438: ****************************************************************/
439:
440: /**
441: * xmlInitMemory:
442: *
443: * Initialize the memory layer.
444: */
445:
446:
447: int
448: xmlInitMemory(void)
449: {
450: int ret;
451:
452: #ifdef DEBUG_MEMORY
453: fprintf(stderr, "xmlInitMemory() Ok\n");
454: #endif
455: ret = 0;
456: return(ret);
457: }
458:
1.2 ! daniel 459: #endif /* ! NO_DEBUG_MEMORY */