blob: 7076f80b63187efd4478bec9be0f400bd4c72481 [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
Daniel Veillard3c558c31999-12-22 11:30:41 +00008#include "win32config.h"
Daniel Veillard7f7d1111999-09-22 09:46:25 +00009#else
10#include "config.h"
11#endif
12
Daniel Veillard6454aec1999-09-02 22:04:43 +000013#include <stdio.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000014#include <string.h>
15
16#ifdef HAVE_SYS_TYPES_H
17#include <sys/types.h>
18#endif
19#ifdef HAVE_TIME_H
20#include <time.h>
21#endif
22#ifdef HAVE_MALLOC_H
Daniel Veillard6454aec1999-09-02 22:04:43 +000023#include <malloc.h>
Daniel Veillard7f7d1111999-09-22 09:46:25 +000024#endif
Daniel Veillard7c1206f1999-10-14 09:10:25 +000025#ifdef HAVE_STDLIB_H
26#include <stdlib.h>
27#endif
28
Daniel Veillard7f7d1111999-09-22 09:46:25 +000029
Daniel Veillard6454aec1999-09-02 22:04:43 +000030#include "xmlmemory.h"
31
32#ifndef NO_DEBUG_MEMORY
Daniel Veillard6454aec1999-09-02 22:04:43 +000033#ifdef xmlMalloc
34#undef xmlMalloc
35#endif
36#ifdef xmlRealloc
37#undef xmlRealloc
38#endif
39#ifdef xmlMemStrdup
40#undef xmlMemStrdup
41#endif
Daniel Veillard00fdf371999-10-08 09:40:39 +000042
Daniel Veillard6454aec1999-09-02 22:04:43 +000043extern void xmlMemoryDump(void);
44
45/*
46 * Each of the blocks allocated begin with a header containing informations
47 */
48
49#define MEMTAG 0x5aa5
50
51#define MALLOC_TYPE 1
52#define REALLOC_TYPE 2
53#define STRDUP_TYPE 3
54
55typedef struct memnod {
56 unsigned int mh_tag;
57 unsigned int mh_type;
58 unsigned long mh_number;
59 size_t mh_size;
60#ifdef MEM_LIST
61 struct memnod *mh_next;
62 struct memnod *mh_prev;
63#endif
64 const char *mh_file;
65 unsigned int mh_line;
66} MEMHDR;
67
68
69#ifdef SUN4
70#define ALIGN_SIZE 16
71#else
72#define ALIGN_SIZE sizeof(double)
73#endif
74#define HDR_SIZE sizeof(MEMHDR)
75#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
76 / ALIGN_SIZE ) * ALIGN_SIZE)
77
78
79#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
80#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
81
82
83static unsigned long debugMemSize = 0;
Daniel Veillard7c1206f1999-10-14 09:10:25 +000084static unsigned long debugMaxMemSize = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +000085static int block=0;
Daniel Veillard7c1206f1999-10-14 09:10:25 +000086int xmlMemStopAtBlock = 0;
87int xmlMemInitialized = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +000088#ifdef MEM_LIST
89static MEMHDR *memlist = NULL;
90#endif
91
92void debugmem_tag_error(void *addr);
93#ifdef MEM_LIST
94void debugmem_list_add(MEMHDR *);
95void debugmem_list_delete(MEMHDR *);
96#endif
97#define Mem_Tag_Err(a) debugmem_tag_error(a);
98
99#ifndef TEST_POINT
100#define TEST_POINT
101#endif
102
103/**
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000104 * xmlMallocBreakpoint:
105 *
106 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
107 * number reaches the specified value this function is called. One need to add a breakpoint
108 * to it to get the context in which the given block is allocated.
109 */
110
111void
112xmlMallocBreakpoint(void) {
113 fprintf(stderr, "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
114}
115
116/**
Daniel Veillard6454aec1999-09-02 22:04:43 +0000117 * xmlMallocLoc:
118 * @size: an int specifying the size in byte to allocate.
119 * @file: the file name or NULL
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000120 @file: the line number
Daniel Veillard6454aec1999-09-02 22:04:43 +0000121 *
122 * a malloc() equivalent, with logging of the allocation info.
123 *
124 * Returns a pointer to the allocated area or NULL in case of lack of memory.
125 */
126
127void *
128xmlMallocLoc(int size, const char * file, int line)
129{
130 MEMHDR *p;
131
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000132 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillard6454aec1999-09-02 22:04:43 +0000133#ifdef DEBUG_MEMORY
134 fprintf(stderr, "Malloc(%d)\n",size);
135#endif
136
137 TEST_POINT
138
139 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
140
141 if (!p) {
Daniel Veillard10a2c651999-12-12 13:03:50 +0000142 fprintf(stderr, "xmlMalloc : Out of free space\n");
143 xmlMemoryDump();
144 return(NULL);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000145 }
146 p->mh_tag = MEMTAG;
147 p->mh_number = ++block;
148 p->mh_size = size;
149 p->mh_type = MALLOC_TYPE;
150 p->mh_file = file;
151 p->mh_line = line;
152 debugMemSize += size;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000153 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000154#ifdef MEM_LIST
155 debugmem_list_add(p);
156#endif
157
158#ifdef DEBUG_MEMORY
159 fprintf(stderr, "Malloc(%d) Ok\n",size);
160#endif
161
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000162 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
Daniel Veillard6454aec1999-09-02 22:04:43 +0000163
164 TEST_POINT
165
166 return(HDR_2_CLIENT(p));
167}
168
169/**
170 * xmlMalloc:
171 * @size: an int specifying the size in byte to allocate.
172 *
173 * a malloc() equivalent, with logging of the allocation info.
174 *
175 * Returns a pointer to the allocated area or NULL in case of lack of memory.
176 */
177
178void *
179xmlMalloc(int size)
180{
181 return(xmlMallocLoc(size, "none", 0));
182}
183
184/**
185 * xmlReallocLoc:
186 * @ptr: the initial memory block pointer
187 * @size: an int specifying the size in byte to allocate.
188 * @file: the file name or NULL
189 * @file: the line number
190 *
191 * a realloc() equivalent, with logging of the allocation info.
192 *
193 * Returns a pointer to the allocated area or NULL in case of lack of memory.
194 */
195
196void *
197xmlReallocLoc(void *ptr,int size, const char * file, int line)
198{
199 MEMHDR *p;
200 unsigned long number;
201
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000202 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillard6454aec1999-09-02 22:04:43 +0000203 TEST_POINT
204
205 p = CLIENT_2_HDR(ptr);
206 number = p->mh_number;
207 if (p->mh_tag != MEMTAG) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000208 Mem_Tag_Err(p);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000209 goto error;
210 }
211 p->mh_tag = ~MEMTAG;
212 debugMemSize -= p->mh_size;
213#ifdef MEM_LIST
214 debugmem_list_delete(p);
215#endif
216
217 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
218 if (!p) {
219 goto error;
220 }
221 p->mh_tag = MEMTAG;
222 p->mh_number = number;
223 p->mh_type = REALLOC_TYPE;
224 p->mh_size = size;
225 p->mh_file = file;
226 p->mh_line = line;
227 debugMemSize += size;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000228 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000229#ifdef MEM_LIST
230 debugmem_list_add(p);
231#endif
232
233 TEST_POINT
234
235 return(HDR_2_CLIENT(p));
236
237error:
238 return(NULL);
239}
240
241/**
242 * xmlRealloc:
243 * @ptr: the initial memory block pointer
244 * @size: an int specifying the size in byte to allocate.
245 *
246 * a realloc() equivalent, with logging of the allocation info.
247 *
248 * Returns a pointer to the allocated area or NULL in case of lack of memory.
249 */
250
251void *
252xmlRealloc(void *ptr,int size) {
253 return(xmlReallocLoc(ptr, size, "none", 0));
254}
255
256/**
257 * xmlFree:
258 * @ptr: the memory block pointer
259 *
260 * a free() equivalent, with error checking.
Daniel Veillard6454aec1999-09-02 22:04:43 +0000261 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000262void
263xmlFree(void *ptr)
264{
265 MEMHDR *p;
266
267 TEST_POINT
268
269 p = CLIENT_2_HDR(ptr);
270 if (p->mh_tag != MEMTAG) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000271 Mem_Tag_Err(p);
272 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000273 }
274 p->mh_tag = ~MEMTAG;
275 debugMemSize -= p->mh_size;
276
277#ifdef MEM_LIST
278 debugmem_list_delete(p);
279#endif
280 free(p);
281
282 TEST_POINT
283
284 return;
285
286error:
287 fprintf(stderr, "xmlFree(%X) error\n", (unsigned int) ptr);
288 return;
289}
290
291/**
292 * xmlMemStrdupLoc:
293 * @ptr: the initial string pointer
294 * @file: the file name or NULL
295 * @file: the line number
296 *
297 * a strdup() equivalent, with logging of the allocation info.
298 *
299 * Returns a pointer to the new string or NULL if allocation error occured.
300 */
301
302char *
303xmlMemStrdupLoc(const char *str, const char *file, int line)
304{
305 char *s;
306 size_t size = strlen(str) + 1;
307 MEMHDR *p;
308
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000309 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillard6454aec1999-09-02 22:04:43 +0000310 TEST_POINT
311
312 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
313 if (!p) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000314 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000315 }
316 p->mh_tag = MEMTAG;
317 p->mh_number = ++block;
318 p->mh_size = size;
319 p->mh_type = STRDUP_TYPE;
320 p->mh_file = file;
321 p->mh_line = line;
322 debugMemSize += size;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000323 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000324#ifdef MEM_LIST
325 debugmem_list_add(p);
326#endif
327 s = HDR_2_CLIENT(p);
328
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000329 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
330
Daniel Veillard6454aec1999-09-02 22:04:43 +0000331 if (s != NULL)
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000332 strcpy(s,str);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000333 else
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000334 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000335
336 TEST_POINT
337
338 return(s);
339
340error:
341 return(NULL);
342}
343
344/**
345 * xmlMemStrdup:
346 * @ptr: the initial string pointer
347 *
348 * a strdup() equivalent, with logging of the allocation info.
349 *
350 * Returns a pointer to the new string or NULL if allocation error occured.
351 */
352
353char *
354xmlMemStrdup(const char *str) {
355 return(xmlMemStrdupLoc(str, "none", 0));
356}
357
358/**
359 * xmlMemUsed:
360 *
361 * returns the amount of memory currenly allocated
362 *
363 * Returns an int representing the amount of memory allocated.
364 */
365
366int
367xmlMemUsed(void) {
368 return(debugMemSize);
369}
370
371/**
372 * xmlMemDisplay:
373 * @fp: a FILE descriptor used as the output file, if NULL, the result is
374 8 written to the file .memorylist
375 *
376 * show in-extenso the memory blocks allocated
377 */
378
379void
380xmlMemDisplay(FILE *fp)
381{
382#ifdef MEM_LIST
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000383 MEMHDR *p;
384 int idx;
385#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
386 time_t currentTime;
387 char buf[500];
388 struct tm * tstruct;
389
390 currentTime = time(NULL);
391 tstruct = localtime(&currentTime);
392 strftime(buf, sizeof(buf) - 1, "%c", tstruct);
393 fprintf(fp," %s\n\n", buf);
394#endif
395
Daniel Veillard6454aec1999-09-02 22:04:43 +0000396
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000397 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
398 debugMemSize, debugMaxMemSize);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000399 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
400 idx = 0;
401 p = memlist;
402 while (p) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000403 fprintf(fp,"%-5u %6lu %6u ",idx++,p->mh_number,p->mh_size);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000404 switch (p->mh_type) {
405 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
406 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
407 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
408 default:fprintf(fp," ??? in ");break;
409 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000410 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000411 if (p->mh_tag != MEMTAG)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000412 fprintf(fp," INVALID");
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000413 fprintf(fp,"\n");
414 p = p->mh_next;
415 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000416#else
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000417 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000418#endif
419}
420
421#ifdef MEM_LIST
422
423void debugmem_list_add(MEMHDR *p)
424{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000425 p->mh_next = memlist;
426 p->mh_prev = NULL;
427 if (memlist) memlist->mh_prev = p;
428 memlist = p;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000429#ifdef MEM_LIST_DEBUG
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000430 if (stderr)
431 Mem_Display(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000432#endif
433}
434
435void debugmem_list_delete(MEMHDR *p)
436{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000437 if (p->mh_next)
438 p->mh_next->mh_prev = p->mh_prev;
439 if (p->mh_prev)
440 p->mh_prev->mh_next = p->mh_next;
441 else memlist = p->mh_next;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000442#ifdef MEM_LIST_DEBUG
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000443 if (stderr)
444 Mem_Display(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000445#endif
446}
447
448#endif
449
450/*
451 * debugmem_tag_error : internal error function.
452 */
453
454void debugmem_tag_error(void *p)
455{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000456 fprintf(stderr, "Memory tag error occurs :%p \n\t bye\n", p);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000457#ifdef MEM_LIST
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000458 if (stderr)
459 xmlMemDisplay(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000460#endif
461}
462
463FILE *xmlMemoryDumpFile = NULL;
464
465
466/**
467 * xmlMemoryDump:
468 *
469 * Dump in-extenso the memory blocks allocated to the file .memorylist
470 */
471
472void
473xmlMemoryDump(void)
474{
475 FILE *dump;
476
477 dump = fopen(".memdump", "w");
478 if (dump == NULL) xmlMemoryDumpFile = stdout;
479 else xmlMemoryDumpFile = dump;
480
481 xmlMemDisplay(xmlMemoryDumpFile);
482
483 if (dump != NULL) fclose(dump);
484}
485
486
487/****************************************************************
488 * *
489 * Initialization Routines *
490 * *
491 ****************************************************************/
492
493/**
494 * xmlInitMemory:
495 *
496 * Initialize the memory layer.
Daniel Veillard00fdf371999-10-08 09:40:39 +0000497 *
498 * Returns 0 on success
Daniel Veillard6454aec1999-09-02 22:04:43 +0000499 */
500
501
502int
503xmlInitMemory(void)
504{
505 int ret;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000506
507#ifdef HAVE_STDLIB_H
508 char *breakpoint;
509
510 breakpoint = getenv("XML_MEM_BREAKPOINT");
511 if (breakpoint != NULL) {
512 sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
513 }
514#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000515
516#ifdef DEBUG_MEMORY
517 fprintf(stderr, "xmlInitMemory() Ok\n");
518#endif
519 ret = 0;
520 return(ret);
521}
522
523#endif /* ! NO_DEBUG_MEMORY */