blob: b4651feb73703a2a1fc9535cb1819f937e6dc6b3 [file] [log] [blame]
Owen Taylor3473f882001-02-23 17:55:21 +00001/*
Daniel Veillard26908ab2002-01-01 16:50:03 +00002 * xmlmemory.c: libxml memory allocator wrapper.
Owen Taylor3473f882001-02-23 17:55:21 +00003 *
Daniel Veillardc5d64342001-06-24 12:13:24 +00004 * daniel@veillard.com
Owen Taylor3473f882001-02-23 17:55:21 +00005 */
6
Daniel Veillard34ce8be2002-03-18 19:37:11 +00007#define IN_LIBXML
Bjorn Reese70a9da52001-04-21 16:57:29 +00008#include "libxml.h"
Owen Taylor3473f882001-02-23 17:55:21 +00009
Owen Taylor3473f882001-02-23 17:55:21 +000010#include <string.h>
11
12#ifdef HAVE_SYS_TYPES_H
13#include <sys/types.h>
14#endif
Daniel Veillard0ba59232002-02-10 13:20:39 +000015
Owen Taylor3473f882001-02-23 17:55:21 +000016#ifdef HAVE_TIME_H
17#include <time.h>
18#endif
Daniel Veillard0ba59232002-02-10 13:20:39 +000019
20#ifdef HAVE_STDLIB_H
21#include <stdlib.h>
22#else
Owen Taylor3473f882001-02-23 17:55:21 +000023#ifdef HAVE_MALLOC_H
24#include <malloc.h>
25#endif
Owen Taylor3473f882001-02-23 17:55:21 +000026#endif
Daniel Veillard0ba59232002-02-10 13:20:39 +000027
Owen Taylor3473f882001-02-23 17:55:21 +000028#ifdef HAVE_CTYPE_H
29#include <ctype.h>
30#endif
31
Daniel Veillard70cab352002-02-06 16:06:58 +000032/**
33 * MEM_LIST:
34 *
35 * keep track of all allocated blocks for error reporting
36 * Always build the memory list !
37 */
38#ifndef MEM_LIST
39#define MEM_LIST /* keep a list of all the allocated memory blocks */
40#endif
Owen Taylor3473f882001-02-23 17:55:21 +000041
42#include <libxml/xmlmemory.h>
Daniel Veillardd0463562001-10-13 09:15:48 +000043#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000044#include <libxml/xmlerror.h>
45
Daniel Veillard56a4cb82001-03-24 17:00:36 +000046void xmlMallocBreakpoint(void);
Daniel Veillard56a4cb82001-03-24 17:00:36 +000047
48/************************************************************************
49 * *
50 * Macros, variables and associated types *
51 * *
52 ************************************************************************/
53
54
Owen Taylor3473f882001-02-23 17:55:21 +000055#ifdef xmlMalloc
56#undef xmlMalloc
57#endif
58#ifdef xmlRealloc
59#undef xmlRealloc
60#endif
61#ifdef xmlMemStrdup
62#undef xmlMemStrdup
63#endif
64
65
66/*
67 * Each of the blocks allocated begin with a header containing informations
68 */
69
70#define MEMTAG 0x5aa5
71
72#define MALLOC_TYPE 1
73#define REALLOC_TYPE 2
74#define STRDUP_TYPE 3
Daniel Veillard3c908dc2003-04-19 00:07:51 +000075#define MALLOC_ATOMIC_TYPE 4
76#define REALLOC_ATOMIC_TYPE 5
Owen Taylor3473f882001-02-23 17:55:21 +000077
78typedef struct memnod {
79 unsigned int mh_tag;
80 unsigned int mh_type;
81 unsigned long mh_number;
82 size_t mh_size;
83#ifdef MEM_LIST
84 struct memnod *mh_next;
85 struct memnod *mh_prev;
86#endif
87 const char *mh_file;
88 unsigned int mh_line;
89} MEMHDR;
90
91
92#ifdef SUN4
93#define ALIGN_SIZE 16
94#else
95#define ALIGN_SIZE sizeof(double)
96#endif
97#define HDR_SIZE sizeof(MEMHDR)
98#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
99 / ALIGN_SIZE ) * ALIGN_SIZE)
100
101
102#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
103#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
104
105
106static unsigned long debugMemSize = 0;
107static unsigned long debugMaxMemSize = 0;
108static int block=0;
Daniel Veillardb44025c2001-10-11 22:55:55 +0000109static int xmlMemStopAtBlock = 0;
110static void *xmlMemTraceBlockAt = NULL;
111static int xmlMemInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000112#ifdef MEM_LIST
113static MEMHDR *memlist = NULL;
114#endif
115
Daniel Veillard01c13b52002-12-10 15:19:08 +0000116static void debugmem_tag_error(void *addr);
Owen Taylor3473f882001-02-23 17:55:21 +0000117#ifdef MEM_LIST
Daniel Veillard01c13b52002-12-10 15:19:08 +0000118static void debugmem_list_add(MEMHDR *);
119static void debugmem_list_delete(MEMHDR *);
Owen Taylor3473f882001-02-23 17:55:21 +0000120#endif
121#define Mem_Tag_Err(a) debugmem_tag_error(a);
122
123#ifndef TEST_POINT
124#define TEST_POINT
125#endif
126
127/**
128 * xmlMallocBreakpoint:
129 *
130 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
131 * number reaches the specified value this function is called. One need to add a breakpoint
132 * to it to get the context in which the given block is allocated.
133 */
134
135void
136xmlMallocBreakpoint(void) {
137 xmlGenericError(xmlGenericErrorContext,
138 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
139}
140
141/**
142 * xmlMallocLoc:
143 * @size: an int specifying the size in byte to allocate.
144 * @file: the file name or NULL
145 * @line: the line number
146 *
147 * a malloc() equivalent, with logging of the allocation info.
148 *
149 * Returns a pointer to the allocated area or NULL in case of lack of memory.
150 */
151
152void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000153xmlMallocLoc(size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000154{
155 MEMHDR *p;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000156 void *ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000157
158 if (!xmlMemInitialized) xmlInitMemory();
159#ifdef DEBUG_MEMORY
160 xmlGenericError(xmlGenericErrorContext,
161 "Malloc(%d)\n",size);
162#endif
163
164 TEST_POINT
165
166 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
167
168 if (!p) {
169 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000170 "xmlMallocLoc : Out of free space\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000171 xmlMemoryDump();
172 return(NULL);
173 }
174 p->mh_tag = MEMTAG;
175 p->mh_number = ++block;
176 p->mh_size = size;
177 p->mh_type = MALLOC_TYPE;
178 p->mh_file = file;
179 p->mh_line = line;
180 debugMemSize += size;
181 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
182#ifdef MEM_LIST
183 debugmem_list_add(p);
184#endif
185
186#ifdef DEBUG_MEMORY
187 xmlGenericError(xmlGenericErrorContext,
188 "Malloc(%d) Ok\n",size);
189#endif
190
191 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
192
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000193 ret = HDR_2_CLIENT(p);
194
195 if (xmlMemTraceBlockAt == ret) {
196 xmlGenericError(xmlGenericErrorContext,
197 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
198 xmlMallocBreakpoint();
199 }
200
Owen Taylor3473f882001-02-23 17:55:21 +0000201 TEST_POINT
202
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000203 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000204}
205
206/**
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000207 * xmlMallocAtomicLoc:
208 * @size: an int specifying the size in byte to allocate.
209 * @file: the file name or NULL
210 * @line: the line number
211 *
212 * a malloc() equivalent, with logging of the allocation info.
213 *
214 * Returns a pointer to the allocated area or NULL in case of lack of memory.
215 */
216
217void *
218xmlMallocAtomicLoc(size_t size, const char * file, int line)
219{
220 MEMHDR *p;
221 void *ret;
222
223 if (!xmlMemInitialized) xmlInitMemory();
224#ifdef DEBUG_MEMORY
225 xmlGenericError(xmlGenericErrorContext,
226 "Malloc(%d)\n",size);
227#endif
228
229 TEST_POINT
230
231 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
232
233 if (!p) {
234 xmlGenericError(xmlGenericErrorContext,
235 "xmlMallocLoc : Out of free space\n");
236 xmlMemoryDump();
237 return(NULL);
238 }
239 p->mh_tag = MEMTAG;
240 p->mh_number = ++block;
241 p->mh_size = size;
242 p->mh_type = MALLOC_ATOMIC_TYPE;
243 p->mh_file = file;
244 p->mh_line = line;
245 debugMemSize += size;
246 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
247#ifdef MEM_LIST
248 debugmem_list_add(p);
249#endif
250
251#ifdef DEBUG_MEMORY
252 xmlGenericError(xmlGenericErrorContext,
253 "Malloc(%d) Ok\n",size);
254#endif
255
256 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
257
258 ret = HDR_2_CLIENT(p);
259
260 if (xmlMemTraceBlockAt == ret) {
261 xmlGenericError(xmlGenericErrorContext,
262 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
263 xmlMallocBreakpoint();
264 }
265
266 TEST_POINT
267
268 return(ret);
269}
270/**
Owen Taylor3473f882001-02-23 17:55:21 +0000271 * xmlMemMalloc:
272 * @size: an int specifying the size in byte to allocate.
273 *
274 * a malloc() equivalent, with logging of the allocation info.
275 *
276 * Returns a pointer to the allocated area or NULL in case of lack of memory.
277 */
278
279void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000280xmlMemMalloc(size_t size)
Owen Taylor3473f882001-02-23 17:55:21 +0000281{
282 return(xmlMallocLoc(size, "none", 0));
283}
284
285/**
286 * xmlReallocLoc:
287 * @ptr: the initial memory block pointer
288 * @size: an int specifying the size in byte to allocate.
289 * @file: the file name or NULL
290 * @line: the line number
291 *
292 * a realloc() equivalent, with logging of the allocation info.
293 *
294 * Returns a pointer to the allocated area or NULL in case of lack of memory.
295 */
296
297void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000298xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000299{
300 MEMHDR *p;
301 unsigned long number;
302
303 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000304 if (ptr == NULL)
305 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000306 TEST_POINT
307
308 p = CLIENT_2_HDR(ptr);
309 number = p->mh_number;
310 if (p->mh_tag != MEMTAG) {
311 Mem_Tag_Err(p);
312 goto error;
313 }
314 p->mh_tag = ~MEMTAG;
315 debugMemSize -= p->mh_size;
316#ifdef MEM_LIST
317 debugmem_list_delete(p);
318#endif
319
320 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
321 if (!p) {
322 goto error;
323 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000324 if (xmlMemTraceBlockAt == ptr) {
325 xmlGenericError(xmlGenericErrorContext,
326 "%p : Realloced(%d -> %d) Ok\n",
327 xmlMemTraceBlockAt, p->mh_size, size);
328 xmlMallocBreakpoint();
329 }
Owen Taylor3473f882001-02-23 17:55:21 +0000330 p->mh_tag = MEMTAG;
331 p->mh_number = number;
332 p->mh_type = REALLOC_TYPE;
333 p->mh_size = size;
334 p->mh_file = file;
335 p->mh_line = line;
336 debugMemSize += size;
337 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
338#ifdef MEM_LIST
339 debugmem_list_add(p);
340#endif
341
342 TEST_POINT
343
344 return(HDR_2_CLIENT(p));
345
346error:
347 return(NULL);
348}
349
350/**
351 * xmlMemRealloc:
352 * @ptr: the initial memory block pointer
353 * @size: an int specifying the size in byte to allocate.
354 *
355 * a realloc() equivalent, with logging of the allocation info.
356 *
357 * Returns a pointer to the allocated area or NULL in case of lack of memory.
358 */
359
360void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000361xmlMemRealloc(void *ptr,size_t size) {
Owen Taylor3473f882001-02-23 17:55:21 +0000362 return(xmlReallocLoc(ptr, size, "none", 0));
363}
364
365/**
366 * xmlMemFree:
367 * @ptr: the memory block pointer
368 *
369 * a free() equivalent, with error checking.
370 */
371void
372xmlMemFree(void *ptr)
373{
374 MEMHDR *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000375 char *target;
Owen Taylor3473f882001-02-23 17:55:21 +0000376
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000377 if (ptr == (void *) -1) {
378 xmlGenericError(xmlGenericErrorContext,
379 "trying to free pointer from freed area\n");
380 goto error;
381 }
382
383 if (xmlMemTraceBlockAt == ptr) {
384 xmlGenericError(xmlGenericErrorContext,
385 "%p : Freed()\n", xmlMemTraceBlockAt);
386 xmlMallocBreakpoint();
387 }
388
Owen Taylor3473f882001-02-23 17:55:21 +0000389 TEST_POINT
390
Daniel Veillard92ad2102001-03-27 12:47:33 +0000391 target = (char *) ptr;
392
Owen Taylor3473f882001-02-23 17:55:21 +0000393 p = CLIENT_2_HDR(ptr);
394 if (p->mh_tag != MEMTAG) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000395 Mem_Tag_Err(p);
396 goto error;
Owen Taylor3473f882001-02-23 17:55:21 +0000397 }
398 p->mh_tag = ~MEMTAG;
399 debugMemSize -= p->mh_size;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000400 memset(target, -1, p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000401
402#ifdef MEM_LIST
403 debugmem_list_delete(p);
404#endif
405 free(p);
406
407 TEST_POINT
408
409 return;
410
411error:
412 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000413 "xmlMemFree(%lX) error\n", (unsigned long) ptr);
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000414 xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000415 return;
416}
417
418/**
419 * xmlMemStrdupLoc:
Daniel Veillard9d06d302002-01-22 18:15:52 +0000420 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000421 * @file: the file name or NULL
422 * @line: the line number
423 *
424 * a strdup() equivalent, with logging of the allocation info.
425 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000426 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000427 */
428
429char *
430xmlMemStrdupLoc(const char *str, const char *file, int line)
431{
432 char *s;
433 size_t size = strlen(str) + 1;
434 MEMHDR *p;
435
436 if (!xmlMemInitialized) xmlInitMemory();
437 TEST_POINT
438
439 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
440 if (!p) {
441 goto error;
442 }
443 p->mh_tag = MEMTAG;
444 p->mh_number = ++block;
445 p->mh_size = size;
446 p->mh_type = STRDUP_TYPE;
447 p->mh_file = file;
448 p->mh_line = line;
449 debugMemSize += size;
450 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
451#ifdef MEM_LIST
452 debugmem_list_add(p);
453#endif
454 s = (char *) HDR_2_CLIENT(p);
455
456 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
457
458 if (s != NULL)
459 strcpy(s,str);
460 else
461 goto error;
462
463 TEST_POINT
464
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000465 if (xmlMemTraceBlockAt == s) {
466 xmlGenericError(xmlGenericErrorContext,
467 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
468 xmlMallocBreakpoint();
469 }
470
Owen Taylor3473f882001-02-23 17:55:21 +0000471 return(s);
472
473error:
474 return(NULL);
475}
476
477/**
478 * xmlMemoryStrdup:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000479 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000480 *
481 * a strdup() equivalent, with logging of the allocation info.
482 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000483 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000484 */
485
486char *
487xmlMemoryStrdup(const char *str) {
488 return(xmlMemStrdupLoc(str, "none", 0));
489}
490
491/**
492 * xmlMemUsed:
493 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000494 * Provides the amount of memory currently allocated
Owen Taylor3473f882001-02-23 17:55:21 +0000495 *
496 * Returns an int representing the amount of memory allocated.
497 */
498
499int
500xmlMemUsed(void) {
501 return(debugMemSize);
502}
503
504#ifdef MEM_LIST
505/**
506 * xmlMemContentShow:
507 * @fp: a FILE descriptor used as the output file
508 * @p: a memory block header
509 *
510 * tries to show some content from the memory block
511 */
512
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000513static void
Owen Taylor3473f882001-02-23 17:55:21 +0000514xmlMemContentShow(FILE *fp, MEMHDR *p)
515{
516 int i,j,len = p->mh_size;
517 const char *buf = (const char *) HDR_2_CLIENT(p);
518
519 if (p == NULL) {
520 fprintf(fp, " NULL");
521 return;
522 }
523
524 for (i = 0;i < len;i++) {
525 if (buf[i] == 0) break;
Daniel Veillard9f28f302002-02-15 20:48:08 +0000526 if (!isprint((unsigned char) buf[i])) break;
Owen Taylor3473f882001-02-23 17:55:21 +0000527 }
528 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
529 if (len >= 4) {
530 MEMHDR *q;
531 void *cur;
532
533 for (j = 0;j < len -3;j += 4) {
534 cur = *((void **) &buf[j]);
535 q = CLIENT_2_HDR(cur);
536 p = memlist;
537 while (p != NULL) {
538 if (p == q) break;
539 p = p->mh_next;
540 }
541 if ((p != NULL) && (p == q)) {
542 fprintf(fp, " pointer to #%lu at index %d",
543 p->mh_number, j);
544 return;
545 }
546 }
547 }
548 } else if ((i == 0) && (buf[i] == 0)) {
549 fprintf(fp," null");
550 } else {
551 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
552 else {
553 fprintf(fp," [");
554 for (j = 0;j < i;j++)
555 fprintf(fp,"%c", buf[j]);
556 fprintf(fp,"]");
557 }
558 }
559}
560#endif
561
562/**
563 * xmlMemShow:
564 * @fp: a FILE descriptor used as the output file
565 * @nr: number of entries to dump
566 *
567 * show a show display of the memory allocated, and dump
568 * the @nr last allocated areas which were not freed
569 */
570
571void
572xmlMemShow(FILE *fp, int nr)
573{
574#ifdef MEM_LIST
575 MEMHDR *p;
576#endif
577
578 if (fp != NULL)
579 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
580 debugMemSize, debugMaxMemSize);
581#ifdef MEM_LIST
582 if (nr > 0) {
583 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
584 p = memlist;
585 while ((p) && nr > 0) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000586 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000587 switch (p->mh_type) {
588 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
589 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000590 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000591 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000592 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
593 default:fprintf(fp," ??? in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000594 }
595 if (p->mh_file != NULL)
596 fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
597 if (p->mh_tag != MEMTAG)
598 fprintf(fp," INVALID");
599 xmlMemContentShow(fp, p);
600 fprintf(fp,"\n");
601 nr--;
602 p = p->mh_next;
603 }
604 }
605#endif /* MEM_LIST */
606}
607
608/**
609 * xmlMemDisplay:
610 * @fp: a FILE descriptor used as the output file, if NULL, the result is
611 * written to the file .memorylist
612 *
613 * show in-extenso the memory blocks allocated
614 */
615
616void
617xmlMemDisplay(FILE *fp)
618{
619#ifdef MEM_LIST
620 MEMHDR *p;
Daniel Veillard144024e2002-02-13 21:14:46 +0000621 unsigned idx;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000622 int nb = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000623#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
624 time_t currentTime;
625 char buf[500];
626 struct tm * tstruct;
627
628 currentTime = time(NULL);
629 tstruct = localtime(&currentTime);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000630 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
Owen Taylor3473f882001-02-23 17:55:21 +0000631 fprintf(fp," %s\n\n", buf);
632#endif
633
634
635 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
636 debugMemSize, debugMaxMemSize);
637 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
638 idx = 0;
639 p = memlist;
640 while (p) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000641 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
642 (unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000643 switch (p->mh_type) {
644 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
645 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
646 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000647 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
648 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000649 default:fprintf(fp," ??? in ");break;
650 }
651 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
652 if (p->mh_tag != MEMTAG)
653 fprintf(fp," INVALID");
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000654 nb++;
655 if (nb < 100)
656 xmlMemContentShow(fp, p);
657 else
658 fprintf(fp," skip");
659
Owen Taylor3473f882001-02-23 17:55:21 +0000660 fprintf(fp,"\n");
661 p = p->mh_next;
662 }
663#else
664 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
665#endif
666}
667
668#ifdef MEM_LIST
669
Daniel Veillard01c13b52002-12-10 15:19:08 +0000670static void debugmem_list_add(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000671{
672 p->mh_next = memlist;
673 p->mh_prev = NULL;
674 if (memlist) memlist->mh_prev = p;
675 memlist = p;
676#ifdef MEM_LIST_DEBUG
677 if (stderr)
678 Mem_Display(stderr);
679#endif
680}
681
Daniel Veillard01c13b52002-12-10 15:19:08 +0000682static void debugmem_list_delete(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000683{
684 if (p->mh_next)
685 p->mh_next->mh_prev = p->mh_prev;
686 if (p->mh_prev)
687 p->mh_prev->mh_next = p->mh_next;
688 else memlist = p->mh_next;
689#ifdef MEM_LIST_DEBUG
690 if (stderr)
691 Mem_Display(stderr);
692#endif
693}
694
695#endif
696
697/*
Daniel Veillard01c13b52002-12-10 15:19:08 +0000698 * debugmem_tag_error:
699 *
700 * internal error function.
Owen Taylor3473f882001-02-23 17:55:21 +0000701 */
702
Daniel Veillard01c13b52002-12-10 15:19:08 +0000703static void debugmem_tag_error(void *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000704{
705 xmlGenericError(xmlGenericErrorContext,
706 "Memory tag error occurs :%p \n\t bye\n", p);
707#ifdef MEM_LIST
708 if (stderr)
709 xmlMemDisplay(stderr);
710#endif
711}
712
Daniel Veillardb44025c2001-10-11 22:55:55 +0000713static FILE *xmlMemoryDumpFile = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000714
715
716/**
717 * xmlMemoryDump:
718 *
719 * Dump in-extenso the memory blocks allocated to the file .memorylist
720 */
721
722void
723xmlMemoryDump(void)
724{
Owen Taylor3473f882001-02-23 17:55:21 +0000725 FILE *dump;
726
Daniel Veillard5997aca2002-03-18 18:36:20 +0000727 if (debugMaxMemSize == 0)
728 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000729 dump = fopen(".memdump", "w");
Daniel Veillardcd337f02001-11-22 18:20:37 +0000730 if (dump == NULL)
731 xmlMemoryDumpFile = stderr;
Owen Taylor3473f882001-02-23 17:55:21 +0000732 else xmlMemoryDumpFile = dump;
733
734 xmlMemDisplay(xmlMemoryDumpFile);
735
736 if (dump != NULL) fclose(dump);
Owen Taylor3473f882001-02-23 17:55:21 +0000737}
738
739
740/****************************************************************
741 * *
742 * Initialization Routines *
743 * *
744 ****************************************************************/
745
Daniel Veillard01c13b52002-12-10 15:19:08 +0000746static int xmlInitMemoryDone = 0;
747
Owen Taylor3473f882001-02-23 17:55:21 +0000748/**
749 * xmlInitMemory:
750 *
751 * Initialize the memory layer.
752 *
753 * Returns 0 on success
754 */
Owen Taylor3473f882001-02-23 17:55:21 +0000755int
756xmlInitMemory(void)
757{
758 int ret;
759
760#ifdef HAVE_STDLIB_H
761 char *breakpoint;
762#endif
763
764 if (xmlInitMemoryDone) return(-1);
765
766#ifdef HAVE_STDLIB_H
767 breakpoint = getenv("XML_MEM_BREAKPOINT");
768 if (breakpoint != NULL) {
769 sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
770 }
771#endif
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000772#ifdef HAVE_STDLIB_H
773 breakpoint = getenv("XML_MEM_TRACE");
774 if (breakpoint != NULL) {
775 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
776 }
777#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000778
779#ifdef DEBUG_MEMORY
780 xmlGenericError(xmlGenericErrorContext,
781 "xmlInitMemory() Ok\n");
782#endif
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000783 xmlMemInitialized = 1;
784 xmlInitMemoryDone = 1;
785
Owen Taylor3473f882001-02-23 17:55:21 +0000786 ret = 0;
787 return(ret);
788}
789
790/**
791 * xmlMemSetup:
792 * @freeFunc: the free() function to use
793 * @mallocFunc: the malloc() function to use
794 * @reallocFunc: the realloc() function to use
795 * @strdupFunc: the strdup() function to use
796 *
797 * Override the default memory access functions with a new set
798 * This has to be called before any other libxml routines !
799 *
800 * Should this be blocked if there was already some allocations
801 * done ?
802 *
803 * Returns 0 on success
804 */
805int
806xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
807 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
808 if (freeFunc == NULL)
809 return(-1);
810 if (mallocFunc == NULL)
811 return(-1);
812 if (reallocFunc == NULL)
813 return(-1);
814 if (strdupFunc == NULL)
815 return(-1);
816 xmlFree = freeFunc;
817 xmlMalloc = mallocFunc;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000818 xmlMallocAtomic = mallocFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000819 xmlRealloc = reallocFunc;
820 xmlMemStrdup = strdupFunc;
821 return(0);
822}
823
824/**
825 * xmlMemGet:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000826 * @freeFunc: place to save the free() function in use
827 * @mallocFunc: place to save the malloc() function in use
828 * @reallocFunc: place to save the realloc() function in use
829 * @strdupFunc: place to save the strdup() function in use
Owen Taylor3473f882001-02-23 17:55:21 +0000830 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000831 * Provides the memory access functions set currently in use
Owen Taylor3473f882001-02-23 17:55:21 +0000832 *
833 * Returns 0 on success
834 */
835int
836xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
837 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
838 if (freeFunc != NULL) *freeFunc = xmlFree;
839 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
840 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
841 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
842 return(0);
843}
844
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000845/**
846 * xmlGcMemSetup:
847 * @freeFunc: the free() function to use
848 * @mallocFunc: the malloc() function to use
849 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
850 * @reallocFunc: the realloc() function to use
851 * @strdupFunc: the strdup() function to use
852 *
853 * Override the default memory access functions with a new set
854 * This has to be called before any other libxml routines !
855 * The mallocAtomicFunc is specialized for atomic block
856 * allocations (i.e. of areas useful for garbage collected memory allocators
857 *
858 * Should this be blocked if there was already some allocations
859 * done ?
860 *
861 * Returns 0 on success
862 */
863int
864xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
865 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
866 xmlStrdupFunc strdupFunc) {
867 if (freeFunc == NULL)
868 return(-1);
869 if (mallocFunc == NULL)
870 return(-1);
871 if (mallocAtomicFunc == NULL)
872 return(-1);
873 if (reallocFunc == NULL)
874 return(-1);
875 if (strdupFunc == NULL)
876 return(-1);
877 xmlFree = freeFunc;
878 xmlMalloc = mallocFunc;
879 xmlMallocAtomic = mallocAtomicFunc;
880 xmlRealloc = reallocFunc;
881 xmlMemStrdup = strdupFunc;
882 return(0);
883}
884
885/**
886 * xmlGcMemGet:
887 * @freeFunc: place to save the free() function in use
888 * @mallocFunc: place to save the malloc() function in use
889 * @mallocAtomicFunc: place to save the atomic malloc() function in use
890 * @reallocFunc: place to save the realloc() function in use
891 * @strdupFunc: place to save the strdup() function in use
892 *
893 * Provides the memory access functions set currently in use
894 * The mallocAtomicFunc is specialized for atomic block
895 * allocations (i.e. of areas useful for garbage collected memory allocators
896 *
897 * Returns 0 on success
898 */
899int
900xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
901 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
902 xmlStrdupFunc *strdupFunc) {
903 if (freeFunc != NULL) *freeFunc = xmlFree;
904 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
905 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
906 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
907 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
908 return(0);
909}
910