blob: 5e304f4175c1b8792c1ede6be60e2621a8c7904e [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
30
31#ifdef xmlMalloc
32#undef xmlMalloc
33#endif
34#ifdef xmlRealloc
35#undef xmlRealloc
36#endif
37#ifdef xmlMemStrdup
38#undef xmlMemStrdup
39#endif
40extern 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.
236 *
237 * Returns a pointer to the allocated area or NULL in case of lack of memory.
238 */
239
240
241void
242xmlFree(void *ptr)
243{
244 MEMHDR *p;
245
246 TEST_POINT
247
248 p = CLIENT_2_HDR(ptr);
249 if (p->mh_tag != MEMTAG) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000250 Mem_Tag_Err(p);
251 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000252 }
253 p->mh_tag = ~MEMTAG;
254 debugMemSize -= p->mh_size;
255
256#ifdef MEM_LIST
257 debugmem_list_delete(p);
258#endif
259 free(p);
260
261 TEST_POINT
262
263 return;
264
265error:
266 fprintf(stderr, "xmlFree(%X) error\n", (unsigned int) ptr);
267 return;
268}
269
270/**
271 * xmlMemStrdupLoc:
272 * @ptr: the initial string pointer
273 * @file: the file name or NULL
274 * @file: the line number
275 *
276 * a strdup() equivalent, with logging of the allocation info.
277 *
278 * Returns a pointer to the new string or NULL if allocation error occured.
279 */
280
281char *
282xmlMemStrdupLoc(const char *str, const char *file, int line)
283{
284 char *s;
285 size_t size = strlen(str) + 1;
286 MEMHDR *p;
287
288 TEST_POINT
289
290 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
291 if (!p) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000292 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000293 }
294 p->mh_tag = MEMTAG;
295 p->mh_number = ++block;
296 p->mh_size = size;
297 p->mh_type = STRDUP_TYPE;
298 p->mh_file = file;
299 p->mh_line = line;
300 debugMemSize += size;
301#ifdef MEM_LIST
302 debugmem_list_add(p);
303#endif
304 s = HDR_2_CLIENT(p);
305
306 if (s != NULL)
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000307 strcpy(s,str);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000308 else
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000309 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000310
311 TEST_POINT
312
313 return(s);
314
315error:
316 return(NULL);
317}
318
319/**
320 * xmlMemStrdup:
321 * @ptr: the initial string pointer
322 *
323 * a strdup() equivalent, with logging of the allocation info.
324 *
325 * Returns a pointer to the new string or NULL if allocation error occured.
326 */
327
328char *
329xmlMemStrdup(const char *str) {
330 return(xmlMemStrdupLoc(str, "none", 0));
331}
332
333/**
334 * xmlMemUsed:
335 *
336 * returns the amount of memory currenly allocated
337 *
338 * Returns an int representing the amount of memory allocated.
339 */
340
341int
342xmlMemUsed(void) {
343 return(debugMemSize);
344}
345
346/**
347 * xmlMemDisplay:
348 * @fp: a FILE descriptor used as the output file, if NULL, the result is
349 8 written to the file .memorylist
350 *
351 * show in-extenso the memory blocks allocated
352 */
353
354void
355xmlMemDisplay(FILE *fp)
356{
357#ifdef MEM_LIST
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000358 MEMHDR *p;
359 int idx;
360#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
361 time_t currentTime;
362 char buf[500];
363 struct tm * tstruct;
364
365 currentTime = time(NULL);
366 tstruct = localtime(&currentTime);
367 strftime(buf, sizeof(buf) - 1, "%c", tstruct);
368 fprintf(fp," %s\n\n", buf);
369#endif
370
Daniel Veillard6454aec1999-09-02 22:04:43 +0000371
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000372 fprintf(fp," MEMORY ALLOCATED : %lu\n",debugMemSize);
373 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
374 idx = 0;
375 p = memlist;
376 while (p) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000377 fprintf(fp,"%-5u %6lu %6u ",idx++,p->mh_number,p->mh_size);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000378 switch (p->mh_type) {
379 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
380 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
381 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
382 default:fprintf(fp," ??? in ");break;
383 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000384 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000385 if (p->mh_tag != MEMTAG)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000386 fprintf(fp," INVALID");
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000387 fprintf(fp,"\n");
388 p = p->mh_next;
389 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000390#else
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000391 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000392#endif
393}
394
395#ifdef MEM_LIST
396
397void debugmem_list_add(MEMHDR *p)
398{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000399 p->mh_next = memlist;
400 p->mh_prev = NULL;
401 if (memlist) memlist->mh_prev = p;
402 memlist = p;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000403#ifdef MEM_LIST_DEBUG
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000404 if (stderr)
405 Mem_Display(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000406#endif
407}
408
409void debugmem_list_delete(MEMHDR *p)
410{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000411 if (p->mh_next)
412 p->mh_next->mh_prev = p->mh_prev;
413 if (p->mh_prev)
414 p->mh_prev->mh_next = p->mh_next;
415 else memlist = p->mh_next;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000416#ifdef MEM_LIST_DEBUG
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000417 if (stderr)
418 Mem_Display(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000419#endif
420}
421
422#endif
423
424/*
425 * debugmem_tag_error : internal error function.
426 */
427
428void debugmem_tag_error(void *p)
429{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000430 fprintf(stderr, "Memory tag error occurs :%p \n\t bye\n", p);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000431#ifdef MEM_LIST
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000432 if (stderr)
433 xmlMemDisplay(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000434#endif
435}
436
437FILE *xmlMemoryDumpFile = NULL;
438
439
440/**
441 * xmlMemoryDump:
442 *
443 * Dump in-extenso the memory blocks allocated to the file .memorylist
444 */
445
446void
447xmlMemoryDump(void)
448{
449 FILE *dump;
450
451 dump = fopen(".memdump", "w");
452 if (dump == NULL) xmlMemoryDumpFile = stdout;
453 else xmlMemoryDumpFile = dump;
454
455 xmlMemDisplay(xmlMemoryDumpFile);
456
457 if (dump != NULL) fclose(dump);
458}
459
460
461/****************************************************************
462 * *
463 * Initialization Routines *
464 * *
465 ****************************************************************/
466
467/**
468 * xmlInitMemory:
469 *
470 * Initialize the memory layer.
471 */
472
473
474int
475xmlInitMemory(void)
476{
477 int ret;
478
479#ifdef DEBUG_MEMORY
480 fprintf(stderr, "xmlInitMemory() Ok\n");
481#endif
482 ret = 0;
483 return(ret);
484}
485
486#endif /* ! NO_DEBUG_MEMORY */