blob: ca9e9c016f7dae9a57abf31f73984ae1945210e6 [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
Daniel Veillard7f7d1111999-09-22 09:46:25 +00007#ifdef WIN32
8#define HAVE_FCNTL_H
9#include <io.h>
10#else
11#include "config.h"
12#endif
13
Daniel Veillard6454aec1999-09-02 22:04:43 +000014#include <stdio.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000015#include <string.h>
16
17#ifdef HAVE_SYS_TYPES_H
18#include <sys/types.h>
19#endif
20#ifdef HAVE_TIME_H
21#include <time.h>
22#endif
23#ifdef HAVE_MALLOC_H
Daniel Veillard6454aec1999-09-02 22:04:43 +000024#include <malloc.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000025#endif
26
Daniel Veillard6454aec1999-09-02 22:04:43 +000027#include "xmlmemory.h"
28
29#ifndef NO_DEBUG_MEMORY
Daniel Veillard6454aec1999-09-02 22:04:43 +000030#ifdef xmlMalloc
31#undef xmlMalloc
32#endif
33#ifdef xmlRealloc
34#undef xmlRealloc
35#endif
36#ifdef xmlMemStrdup
37#undef xmlMemStrdup
38#endif
Daniel Veillard00fdf371999-10-08 09:40:39 +000039
Daniel Veillard6454aec1999-09-02 22:04:43 +000040extern void xmlMemoryDump(void);
41
42/*
43 * Each of the blocks allocated begin with a header containing informations
44 */
45
46#define MEMTAG 0x5aa5
47
48#define MALLOC_TYPE 1
49#define REALLOC_TYPE 2
50#define STRDUP_TYPE 3
51
52typedef struct memnod {
53 unsigned int mh_tag;
54 unsigned int mh_type;
55 unsigned long mh_number;
56 size_t mh_size;
57#ifdef MEM_LIST
58 struct memnod *mh_next;
59 struct memnod *mh_prev;
60#endif
61 const char *mh_file;
62 unsigned int mh_line;
63} MEMHDR;
64
65
66#ifdef SUN4
67#define ALIGN_SIZE 16
68#else
69#define ALIGN_SIZE sizeof(double)
70#endif
71#define HDR_SIZE sizeof(MEMHDR)
72#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
73 / ALIGN_SIZE ) * ALIGN_SIZE)
74
75
76#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
77#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
78
79
80static unsigned long debugMemSize = 0;
81static int block=0;
82#ifdef MEM_LIST
83static MEMHDR *memlist = NULL;
84#endif
85
86void debugmem_tag_error(void *addr);
87#ifdef MEM_LIST
88void debugmem_list_add(MEMHDR *);
89void debugmem_list_delete(MEMHDR *);
90#endif
91#define Mem_Tag_Err(a) debugmem_tag_error(a);
92
93#ifndef TEST_POINT
94#define TEST_POINT
95#endif
96
97/**
98 * xmlMallocLoc:
99 * @size: an int specifying the size in byte to allocate.
100 * @file: the file name or NULL
101 * @file: the line number
102 *
103 * a malloc() equivalent, with logging of the allocation info.
104 *
105 * Returns a pointer to the allocated area or NULL in case of lack of memory.
106 */
107
108void *
109xmlMallocLoc(int size, const char * file, int line)
110{
111 MEMHDR *p;
112
113#ifdef DEBUG_MEMORY
114 fprintf(stderr, "Malloc(%d)\n",size);
115#endif
116
117 TEST_POINT
118
119 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
120
121 if (!p) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000122 fprintf(stderr, "xmlMalloc : Out of free space\n");
123 xmlMemoryDump();
Daniel Veillard6454aec1999-09-02 22:04:43 +0000124 }
125 p->mh_tag = MEMTAG;
126 p->mh_number = ++block;
127 p->mh_size = size;
128 p->mh_type = MALLOC_TYPE;
129 p->mh_file = file;
130 p->mh_line = line;
131 debugMemSize += size;
132#ifdef MEM_LIST
133 debugmem_list_add(p);
134#endif
135
136#ifdef DEBUG_MEMORY
137 fprintf(stderr, "Malloc(%d) Ok\n",size);
138#endif
139
140
141 TEST_POINT
142
143 return(HDR_2_CLIENT(p));
144}
145
146/**
147 * xmlMalloc:
148 * @size: an int specifying the size in byte to allocate.
149 *
150 * a malloc() equivalent, with logging of the allocation info.
151 *
152 * Returns a pointer to the allocated area or NULL in case of lack of memory.
153 */
154
155void *
156xmlMalloc(int size)
157{
158 return(xmlMallocLoc(size, "none", 0));
159}
160
161/**
162 * xmlReallocLoc:
163 * @ptr: the initial memory block pointer
164 * @size: an int specifying the size in byte to allocate.
165 * @file: the file name or NULL
166 * @file: the line number
167 *
168 * a realloc() equivalent, with logging of the allocation info.
169 *
170 * Returns a pointer to the allocated area or NULL in case of lack of memory.
171 */
172
173void *
174xmlReallocLoc(void *ptr,int size, const char * file, int line)
175{
176 MEMHDR *p;
177 unsigned long number;
178
179 TEST_POINT
180
181 p = CLIENT_2_HDR(ptr);
182 number = p->mh_number;
183 if (p->mh_tag != MEMTAG) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000184 Mem_Tag_Err(p);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000185 goto error;
186 }
187 p->mh_tag = ~MEMTAG;
188 debugMemSize -= p->mh_size;
189#ifdef MEM_LIST
190 debugmem_list_delete(p);
191#endif
192
193 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
194 if (!p) {
195 goto error;
196 }
197 p->mh_tag = MEMTAG;
198 p->mh_number = number;
199 p->mh_type = REALLOC_TYPE;
200 p->mh_size = size;
201 p->mh_file = file;
202 p->mh_line = line;
203 debugMemSize += size;
204#ifdef MEM_LIST
205 debugmem_list_add(p);
206#endif
207
208 TEST_POINT
209
210 return(HDR_2_CLIENT(p));
211
212error:
213 return(NULL);
214}
215
216/**
217 * xmlRealloc:
218 * @ptr: the initial memory block pointer
219 * @size: an int specifying the size in byte to allocate.
220 *
221 * a realloc() equivalent, with logging of the allocation info.
222 *
223 * Returns a pointer to the allocated area or NULL in case of lack of memory.
224 */
225
226void *
227xmlRealloc(void *ptr,int size) {
228 return(xmlReallocLoc(ptr, size, "none", 0));
229}
230
231/**
232 * xmlFree:
233 * @ptr: the memory block pointer
234 *
235 * a free() equivalent, with error checking.
Daniel Veillard6454aec1999-09-02 22:04:43 +0000236 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000237void
238xmlFree(void *ptr)
239{
240 MEMHDR *p;
241
242 TEST_POINT
243
244 p = CLIENT_2_HDR(ptr);
245 if (p->mh_tag != MEMTAG) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000246 Mem_Tag_Err(p);
247 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000248 }
249 p->mh_tag = ~MEMTAG;
250 debugMemSize -= p->mh_size;
251
252#ifdef MEM_LIST
253 debugmem_list_delete(p);
254#endif
255 free(p);
256
257 TEST_POINT
258
259 return;
260
261error:
262 fprintf(stderr, "xmlFree(%X) error\n", (unsigned int) ptr);
263 return;
264}
265
266/**
267 * xmlMemStrdupLoc:
268 * @ptr: the initial string pointer
269 * @file: the file name or NULL
270 * @file: the line number
271 *
272 * a strdup() equivalent, with logging of the allocation info.
273 *
274 * Returns a pointer to the new string or NULL if allocation error occured.
275 */
276
277char *
278xmlMemStrdupLoc(const char *str, const char *file, int line)
279{
280 char *s;
281 size_t size = strlen(str) + 1;
282 MEMHDR *p;
283
284 TEST_POINT
285
286 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
287 if (!p) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000288 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000289 }
290 p->mh_tag = MEMTAG;
291 p->mh_number = ++block;
292 p->mh_size = size;
293 p->mh_type = STRDUP_TYPE;
294 p->mh_file = file;
295 p->mh_line = line;
296 debugMemSize += size;
297#ifdef MEM_LIST
298 debugmem_list_add(p);
299#endif
300 s = HDR_2_CLIENT(p);
301
302 if (s != NULL)
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000303 strcpy(s,str);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000304 else
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000305 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000306
307 TEST_POINT
308
309 return(s);
310
311error:
312 return(NULL);
313}
314
315/**
316 * xmlMemStrdup:
317 * @ptr: the initial string pointer
318 *
319 * a strdup() equivalent, with logging of the allocation info.
320 *
321 * Returns a pointer to the new string or NULL if allocation error occured.
322 */
323
324char *
325xmlMemStrdup(const char *str) {
326 return(xmlMemStrdupLoc(str, "none", 0));
327}
328
329/**
330 * xmlMemUsed:
331 *
332 * returns the amount of memory currenly allocated
333 *
334 * Returns an int representing the amount of memory allocated.
335 */
336
337int
338xmlMemUsed(void) {
339 return(debugMemSize);
340}
341
342/**
343 * xmlMemDisplay:
344 * @fp: a FILE descriptor used as the output file, if NULL, the result is
345 8 written to the file .memorylist
346 *
347 * show in-extenso the memory blocks allocated
348 */
349
350void
351xmlMemDisplay(FILE *fp)
352{
353#ifdef MEM_LIST
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000354 MEMHDR *p;
355 int idx;
356#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
357 time_t currentTime;
358 char buf[500];
359 struct tm * tstruct;
360
361 currentTime = time(NULL);
362 tstruct = localtime(&currentTime);
363 strftime(buf, sizeof(buf) - 1, "%c", tstruct);
364 fprintf(fp," %s\n\n", buf);
365#endif
366
Daniel Veillard6454aec1999-09-02 22:04:43 +0000367
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000368 fprintf(fp," MEMORY ALLOCATED : %lu\n",debugMemSize);
369 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
370 idx = 0;
371 p = memlist;
372 while (p) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000373 fprintf(fp,"%-5u %6lu %6u ",idx++,p->mh_number,p->mh_size);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000374 switch (p->mh_type) {
375 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
376 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
377 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
378 default:fprintf(fp," ??? in ");break;
379 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000380 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000381 if (p->mh_tag != MEMTAG)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000382 fprintf(fp," INVALID");
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000383 fprintf(fp,"\n");
384 p = p->mh_next;
385 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000386#else
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000387 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000388#endif
389}
390
391#ifdef MEM_LIST
392
393void debugmem_list_add(MEMHDR *p)
394{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000395 p->mh_next = memlist;
396 p->mh_prev = NULL;
397 if (memlist) memlist->mh_prev = p;
398 memlist = p;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000399#ifdef MEM_LIST_DEBUG
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000400 if (stderr)
401 Mem_Display(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000402#endif
403}
404
405void debugmem_list_delete(MEMHDR *p)
406{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000407 if (p->mh_next)
408 p->mh_next->mh_prev = p->mh_prev;
409 if (p->mh_prev)
410 p->mh_prev->mh_next = p->mh_next;
411 else memlist = p->mh_next;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000412#ifdef MEM_LIST_DEBUG
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000413 if (stderr)
414 Mem_Display(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000415#endif
416}
417
418#endif
419
420/*
421 * debugmem_tag_error : internal error function.
422 */
423
424void debugmem_tag_error(void *p)
425{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000426 fprintf(stderr, "Memory tag error occurs :%p \n\t bye\n", p);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000427#ifdef MEM_LIST
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000428 if (stderr)
429 xmlMemDisplay(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000430#endif
431}
432
433FILE *xmlMemoryDumpFile = NULL;
434
435
436/**
437 * xmlMemoryDump:
438 *
439 * Dump in-extenso the memory blocks allocated to the file .memorylist
440 */
441
442void
443xmlMemoryDump(void)
444{
445 FILE *dump;
446
447 dump = fopen(".memdump", "w");
448 if (dump == NULL) xmlMemoryDumpFile = stdout;
449 else xmlMemoryDumpFile = dump;
450
451 xmlMemDisplay(xmlMemoryDumpFile);
452
453 if (dump != NULL) fclose(dump);
454}
455
456
457/****************************************************************
458 * *
459 * Initialization Routines *
460 * *
461 ****************************************************************/
462
463/**
464 * xmlInitMemory:
465 *
466 * Initialize the memory layer.
Daniel Veillard00fdf371999-10-08 09:40:39 +0000467 *
468 * Returns 0 on success
Daniel Veillard6454aec1999-09-02 22:04:43 +0000469 */
470
471
472int
473xmlInitMemory(void)
474{
475 int ret;
476
477#ifdef DEBUG_MEMORY
478 fprintf(stderr, "xmlInitMemory() Ok\n");
479#endif
480 ret = 0;
481 return(ret);
482}
483
484#endif /* ! NO_DEBUG_MEMORY */