blob: e3341da25159a2ef9cc0e205360e1c13567aa254 [file] [log] [blame]
Daniel Veillard6454aec1999-09-02 22:04:43 +00001/*
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
13#ifndef NO_DEBUG_MEMORY
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
24extern 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
36typedef 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
64static unsigned long debugMemSize = 0;
65static int block=0;
66#ifdef MEM_LIST
67static MEMHDR *memlist = NULL;
68#endif
69
70void debugmem_tag_error(void *addr);
71#ifdef MEM_LIST
72void debugmem_list_add(MEMHDR *);
73void 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
92void *
93xmlMallocLoc(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
139void *
140xmlMalloc(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
157void *
158xmlReallocLoc(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
196error:
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
210void *
211xmlRealloc(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
225void
226xmlFree(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
249error:
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
265char *
266xmlMemStrdupLoc(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
299error:
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
312char *
313xmlMemStrdup(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
325int
326xmlMemUsed(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
338void
339xmlMemDisplay(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
370void 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
382void 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
401void 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
410FILE *xmlMemoryDumpFile = NULL;
411
412
413/**
414 * xmlMemoryDump:
415 *
416 * Dump in-extenso the memory blocks allocated to the file .memorylist
417 */
418
419void
420xmlMemoryDump(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
447int
448xmlInitMemory(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
459#endif /* ! NO_DEBUG_MEMORY */