blob: 19150527f8a19518533a9e2e256378c7e455c6a6 [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
Daniel Veillard7c1206f1999-10-14 09:10:25 +000026#ifdef HAVE_STDLIB_H
27#include <stdlib.h>
28#endif
29
Daniel Veillard7f7d1111999-09-22 09:46:25 +000030
Daniel Veillard6454aec1999-09-02 22:04:43 +000031#include "xmlmemory.h"
32
33#ifndef NO_DEBUG_MEMORY
Daniel Veillard6454aec1999-09-02 22:04:43 +000034#ifdef xmlMalloc
35#undef xmlMalloc
36#endif
37#ifdef xmlRealloc
38#undef xmlRealloc
39#endif
40#ifdef xmlMemStrdup
41#undef xmlMemStrdup
42#endif
Daniel Veillard00fdf371999-10-08 09:40:39 +000043
Daniel Veillard6454aec1999-09-02 22:04:43 +000044extern void xmlMemoryDump(void);
45
46/*
47 * Each of the blocks allocated begin with a header containing informations
48 */
49
50#define MEMTAG 0x5aa5
51
52#define MALLOC_TYPE 1
53#define REALLOC_TYPE 2
54#define STRDUP_TYPE 3
55
56typedef struct memnod {
57 unsigned int mh_tag;
58 unsigned int mh_type;
59 unsigned long mh_number;
60 size_t mh_size;
61#ifdef MEM_LIST
62 struct memnod *mh_next;
63 struct memnod *mh_prev;
64#endif
65 const char *mh_file;
66 unsigned int mh_line;
67} MEMHDR;
68
69
70#ifdef SUN4
71#define ALIGN_SIZE 16
72#else
73#define ALIGN_SIZE sizeof(double)
74#endif
75#define HDR_SIZE sizeof(MEMHDR)
76#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
77 / ALIGN_SIZE ) * ALIGN_SIZE)
78
79
80#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
81#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
82
83
84static unsigned long debugMemSize = 0;
Daniel Veillard7c1206f1999-10-14 09:10:25 +000085static unsigned long debugMaxMemSize = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +000086static int block=0;
Daniel Veillard7c1206f1999-10-14 09:10:25 +000087int xmlMemStopAtBlock = 0;
88int xmlMemInitialized = 0;
Daniel Veillard6454aec1999-09-02 22:04:43 +000089#ifdef MEM_LIST
90static MEMHDR *memlist = NULL;
91#endif
92
93void debugmem_tag_error(void *addr);
94#ifdef MEM_LIST
95void debugmem_list_add(MEMHDR *);
96void debugmem_list_delete(MEMHDR *);
97#endif
98#define Mem_Tag_Err(a) debugmem_tag_error(a);
99
100#ifndef TEST_POINT
101#define TEST_POINT
102#endif
103
104/**
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000105 * xmlMallocBreakpoint:
106 *
107 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
108 * number reaches the specified value this function is called. One need to add a breakpoint
109 * to it to get the context in which the given block is allocated.
110 */
111
112void
113xmlMallocBreakpoint(void) {
114 fprintf(stderr, "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
115}
116
117/**
Daniel Veillard6454aec1999-09-02 22:04:43 +0000118 * xmlMallocLoc:
119 * @size: an int specifying the size in byte to allocate.
120 * @file: the file name or NULL
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000121 @file: the line number
Daniel Veillard6454aec1999-09-02 22:04:43 +0000122 *
123 * a malloc() equivalent, with logging of the allocation info.
124 *
125 * Returns a pointer to the allocated area or NULL in case of lack of memory.
126 */
127
128void *
129xmlMallocLoc(int size, const char * file, int line)
130{
131 MEMHDR *p;
132
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000133 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillard6454aec1999-09-02 22:04:43 +0000134#ifdef DEBUG_MEMORY
135 fprintf(stderr, "Malloc(%d)\n",size);
136#endif
137
138 TEST_POINT
139
140 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
141
142 if (!p) {
Daniel Veillard10a2c651999-12-12 13:03:50 +0000143 fprintf(stderr, "xmlMalloc : Out of free space\n");
144 xmlMemoryDump();
145 return(NULL);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000146 }
147 p->mh_tag = MEMTAG;
148 p->mh_number = ++block;
149 p->mh_size = size;
150 p->mh_type = MALLOC_TYPE;
151 p->mh_file = file;
152 p->mh_line = line;
153 debugMemSize += size;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000154 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000155#ifdef MEM_LIST
156 debugmem_list_add(p);
157#endif
158
159#ifdef DEBUG_MEMORY
160 fprintf(stderr, "Malloc(%d) Ok\n",size);
161#endif
162
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000163 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
Daniel Veillard6454aec1999-09-02 22:04:43 +0000164
165 TEST_POINT
166
167 return(HDR_2_CLIENT(p));
168}
169
170/**
171 * xmlMalloc:
172 * @size: an int specifying the size in byte to allocate.
173 *
174 * a malloc() equivalent, with logging of the allocation info.
175 *
176 * Returns a pointer to the allocated area or NULL in case of lack of memory.
177 */
178
179void *
180xmlMalloc(int size)
181{
182 return(xmlMallocLoc(size, "none", 0));
183}
184
185/**
186 * xmlReallocLoc:
187 * @ptr: the initial memory block pointer
188 * @size: an int specifying the size in byte to allocate.
189 * @file: the file name or NULL
190 * @file: the line number
191 *
192 * a realloc() equivalent, with logging of the allocation info.
193 *
194 * Returns a pointer to the allocated area or NULL in case of lack of memory.
195 */
196
197void *
198xmlReallocLoc(void *ptr,int size, const char * file, int line)
199{
200 MEMHDR *p;
201 unsigned long number;
202
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000203 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillard6454aec1999-09-02 22:04:43 +0000204 TEST_POINT
205
206 p = CLIENT_2_HDR(ptr);
207 number = p->mh_number;
208 if (p->mh_tag != MEMTAG) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000209 Mem_Tag_Err(p);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000210 goto error;
211 }
212 p->mh_tag = ~MEMTAG;
213 debugMemSize -= p->mh_size;
214#ifdef MEM_LIST
215 debugmem_list_delete(p);
216#endif
217
218 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
219 if (!p) {
220 goto error;
221 }
222 p->mh_tag = MEMTAG;
223 p->mh_number = number;
224 p->mh_type = REALLOC_TYPE;
225 p->mh_size = size;
226 p->mh_file = file;
227 p->mh_line = line;
228 debugMemSize += size;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000229 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000230#ifdef MEM_LIST
231 debugmem_list_add(p);
232#endif
233
234 TEST_POINT
235
236 return(HDR_2_CLIENT(p));
237
238error:
239 return(NULL);
240}
241
242/**
243 * xmlRealloc:
244 * @ptr: the initial memory block pointer
245 * @size: an int specifying the size in byte to allocate.
246 *
247 * a realloc() equivalent, with logging of the allocation info.
248 *
249 * Returns a pointer to the allocated area or NULL in case of lack of memory.
250 */
251
252void *
253xmlRealloc(void *ptr,int size) {
254 return(xmlReallocLoc(ptr, size, "none", 0));
255}
256
257/**
258 * xmlFree:
259 * @ptr: the memory block pointer
260 *
261 * a free() equivalent, with error checking.
Daniel Veillard6454aec1999-09-02 22:04:43 +0000262 */
Daniel Veillard6454aec1999-09-02 22:04:43 +0000263void
264xmlFree(void *ptr)
265{
266 MEMHDR *p;
267
268 TEST_POINT
269
270 p = CLIENT_2_HDR(ptr);
271 if (p->mh_tag != MEMTAG) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000272 Mem_Tag_Err(p);
273 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000274 }
275 p->mh_tag = ~MEMTAG;
276 debugMemSize -= p->mh_size;
277
278#ifdef MEM_LIST
279 debugmem_list_delete(p);
280#endif
281 free(p);
282
283 TEST_POINT
284
285 return;
286
287error:
288 fprintf(stderr, "xmlFree(%X) error\n", (unsigned int) ptr);
289 return;
290}
291
292/**
293 * xmlMemStrdupLoc:
294 * @ptr: the initial string pointer
295 * @file: the file name or NULL
296 * @file: the line number
297 *
298 * a strdup() equivalent, with logging of the allocation info.
299 *
300 * Returns a pointer to the new string or NULL if allocation error occured.
301 */
302
303char *
304xmlMemStrdupLoc(const char *str, const char *file, int line)
305{
306 char *s;
307 size_t size = strlen(str) + 1;
308 MEMHDR *p;
309
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000310 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillard6454aec1999-09-02 22:04:43 +0000311 TEST_POINT
312
313 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
314 if (!p) {
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000315 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000316 }
317 p->mh_tag = MEMTAG;
318 p->mh_number = ++block;
319 p->mh_size = size;
320 p->mh_type = STRDUP_TYPE;
321 p->mh_file = file;
322 p->mh_line = line;
323 debugMemSize += size;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000324 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000325#ifdef MEM_LIST
326 debugmem_list_add(p);
327#endif
328 s = HDR_2_CLIENT(p);
329
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000330 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
331
Daniel Veillard6454aec1999-09-02 22:04:43 +0000332 if (s != NULL)
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000333 strcpy(s,str);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000334 else
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000335 goto error;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000336
337 TEST_POINT
338
339 return(s);
340
341error:
342 return(NULL);
343}
344
345/**
346 * xmlMemStrdup:
347 * @ptr: the initial string pointer
348 *
349 * a strdup() equivalent, with logging of the allocation info.
350 *
351 * Returns a pointer to the new string or NULL if allocation error occured.
352 */
353
354char *
355xmlMemStrdup(const char *str) {
356 return(xmlMemStrdupLoc(str, "none", 0));
357}
358
359/**
360 * xmlMemUsed:
361 *
362 * returns the amount of memory currenly allocated
363 *
364 * Returns an int representing the amount of memory allocated.
365 */
366
367int
368xmlMemUsed(void) {
369 return(debugMemSize);
370}
371
372/**
373 * xmlMemDisplay:
374 * @fp: a FILE descriptor used as the output file, if NULL, the result is
375 8 written to the file .memorylist
376 *
377 * show in-extenso the memory blocks allocated
378 */
379
380void
381xmlMemDisplay(FILE *fp)
382{
383#ifdef MEM_LIST
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000384 MEMHDR *p;
385 int idx;
386#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
387 time_t currentTime;
388 char buf[500];
389 struct tm * tstruct;
390
391 currentTime = time(NULL);
392 tstruct = localtime(&currentTime);
393 strftime(buf, sizeof(buf) - 1, "%c", tstruct);
394 fprintf(fp," %s\n\n", buf);
395#endif
396
Daniel Veillard6454aec1999-09-02 22:04:43 +0000397
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000398 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
399 debugMemSize, debugMaxMemSize);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000400 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
401 idx = 0;
402 p = memlist;
403 while (p) {
Daniel Veillard6454aec1999-09-02 22:04:43 +0000404 fprintf(fp,"%-5u %6lu %6u ",idx++,p->mh_number,p->mh_size);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000405 switch (p->mh_type) {
406 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
407 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
408 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
409 default:fprintf(fp," ??? in ");break;
410 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000411 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000412 if (p->mh_tag != MEMTAG)
Daniel Veillard6454aec1999-09-02 22:04:43 +0000413 fprintf(fp," INVALID");
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000414 fprintf(fp,"\n");
415 p = p->mh_next;
416 }
Daniel Veillard6454aec1999-09-02 22:04:43 +0000417#else
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000418 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
Daniel Veillard6454aec1999-09-02 22:04:43 +0000419#endif
420}
421
422#ifdef MEM_LIST
423
424void debugmem_list_add(MEMHDR *p)
425{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000426 p->mh_next = memlist;
427 p->mh_prev = NULL;
428 if (memlist) memlist->mh_prev = p;
429 memlist = p;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000430#ifdef MEM_LIST_DEBUG
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000431 if (stderr)
432 Mem_Display(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000433#endif
434}
435
436void debugmem_list_delete(MEMHDR *p)
437{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000438 if (p->mh_next)
439 p->mh_next->mh_prev = p->mh_prev;
440 if (p->mh_prev)
441 p->mh_prev->mh_next = p->mh_next;
442 else memlist = p->mh_next;
Daniel Veillard6454aec1999-09-02 22:04:43 +0000443#ifdef MEM_LIST_DEBUG
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000444 if (stderr)
445 Mem_Display(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000446#endif
447}
448
449#endif
450
451/*
452 * debugmem_tag_error : internal error function.
453 */
454
455void debugmem_tag_error(void *p)
456{
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000457 fprintf(stderr, "Memory tag error occurs :%p \n\t bye\n", p);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000458#ifdef MEM_LIST
Daniel Veillard7f7d1111999-09-22 09:46:25 +0000459 if (stderr)
460 xmlMemDisplay(stderr);
Daniel Veillard6454aec1999-09-02 22:04:43 +0000461#endif
462}
463
464FILE *xmlMemoryDumpFile = NULL;
465
466
467/**
468 * xmlMemoryDump:
469 *
470 * Dump in-extenso the memory blocks allocated to the file .memorylist
471 */
472
473void
474xmlMemoryDump(void)
475{
476 FILE *dump;
477
478 dump = fopen(".memdump", "w");
479 if (dump == NULL) xmlMemoryDumpFile = stdout;
480 else xmlMemoryDumpFile = dump;
481
482 xmlMemDisplay(xmlMemoryDumpFile);
483
484 if (dump != NULL) fclose(dump);
485}
486
487
488/****************************************************************
489 * *
490 * Initialization Routines *
491 * *
492 ****************************************************************/
493
494/**
495 * xmlInitMemory:
496 *
497 * Initialize the memory layer.
Daniel Veillard00fdf371999-10-08 09:40:39 +0000498 *
499 * Returns 0 on success
Daniel Veillard6454aec1999-09-02 22:04:43 +0000500 */
501
502
503int
504xmlInitMemory(void)
505{
506 int ret;
Daniel Veillard7c1206f1999-10-14 09:10:25 +0000507
508#ifdef HAVE_STDLIB_H
509 char *breakpoint;
510
511 breakpoint = getenv("XML_MEM_BREAKPOINT");
512 if (breakpoint != NULL) {
513 sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
514 }
515#endif
Daniel Veillard6454aec1999-09-02 22:04:43 +0000516
517#ifdef DEBUG_MEMORY
518 fprintf(stderr, "xmlInitMemory() Ok\n");
519#endif
520 ret = 0;
521 return(ret);
522}
523
524#endif /* ! NO_DEBUG_MEMORY */