blob: e20f721f069aa35337fa6c82df834b3c05c61b69 [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 Veillard4432df22003-09-28 18:58:27 +000032
Daniel Veillard70cab352002-02-06 16:06:58 +000033/**
34 * MEM_LIST:
35 *
36 * keep track of all allocated blocks for error reporting
37 * Always build the memory list !
38 */
39#ifndef MEM_LIST
40#define MEM_LIST /* keep a list of all the allocated memory blocks */
41#endif
Owen Taylor3473f882001-02-23 17:55:21 +000042
43#include <libxml/xmlmemory.h>
Daniel Veillardd0463562001-10-13 09:15:48 +000044#include <libxml/globals.h>
Owen Taylor3473f882001-02-23 17:55:21 +000045#include <libxml/xmlerror.h>
46
Daniel Veillard4432df22003-09-28 18:58:27 +000047static int xmlMemInitialized = 0;
48
49#ifdef DEBUG_MEMORY_LOCATION
Daniel Veillard56a4cb82001-03-24 17:00:36 +000050void xmlMallocBreakpoint(void);
Daniel Veillard56a4cb82001-03-24 17:00:36 +000051
52/************************************************************************
53 * *
54 * Macros, variables and associated types *
55 * *
56 ************************************************************************/
57
58
Owen Taylor3473f882001-02-23 17:55:21 +000059#ifdef xmlMalloc
60#undef xmlMalloc
61#endif
62#ifdef xmlRealloc
63#undef xmlRealloc
64#endif
65#ifdef xmlMemStrdup
66#undef xmlMemStrdup
67#endif
68
69
70/*
71 * Each of the blocks allocated begin with a header containing informations
72 */
73
74#define MEMTAG 0x5aa5
75
76#define MALLOC_TYPE 1
77#define REALLOC_TYPE 2
78#define STRDUP_TYPE 3
Daniel Veillard3c908dc2003-04-19 00:07:51 +000079#define MALLOC_ATOMIC_TYPE 4
80#define REALLOC_ATOMIC_TYPE 5
Owen Taylor3473f882001-02-23 17:55:21 +000081
82typedef struct memnod {
83 unsigned int mh_tag;
84 unsigned int mh_type;
85 unsigned long mh_number;
86 size_t mh_size;
87#ifdef MEM_LIST
88 struct memnod *mh_next;
89 struct memnod *mh_prev;
90#endif
91 const char *mh_file;
92 unsigned int mh_line;
93} MEMHDR;
94
95
96#ifdef SUN4
97#define ALIGN_SIZE 16
98#else
99#define ALIGN_SIZE sizeof(double)
100#endif
101#define HDR_SIZE sizeof(MEMHDR)
102#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
103 / ALIGN_SIZE ) * ALIGN_SIZE)
104
105
106#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
107#define HDR_2_CLIENT(a) ((void *) (((char *) (a)) + RESERVE_SIZE))
108
109
110static unsigned long debugMemSize = 0;
111static unsigned long debugMaxMemSize = 0;
112static int block=0;
Daniel Veillardb44025c2001-10-11 22:55:55 +0000113static int xmlMemStopAtBlock = 0;
114static void *xmlMemTraceBlockAt = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000115#ifdef MEM_LIST
116static MEMHDR *memlist = NULL;
117#endif
118
Daniel Veillard01c13b52002-12-10 15:19:08 +0000119static void debugmem_tag_error(void *addr);
Owen Taylor3473f882001-02-23 17:55:21 +0000120#ifdef MEM_LIST
Daniel Veillard01c13b52002-12-10 15:19:08 +0000121static void debugmem_list_add(MEMHDR *);
122static void debugmem_list_delete(MEMHDR *);
Owen Taylor3473f882001-02-23 17:55:21 +0000123#endif
124#define Mem_Tag_Err(a) debugmem_tag_error(a);
125
126#ifndef TEST_POINT
127#define TEST_POINT
128#endif
129
130/**
131 * xmlMallocBreakpoint:
132 *
133 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
134 * number reaches the specified value this function is called. One need to add a breakpoint
135 * to it to get the context in which the given block is allocated.
136 */
137
138void
139xmlMallocBreakpoint(void) {
140 xmlGenericError(xmlGenericErrorContext,
141 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
142}
143
144/**
145 * xmlMallocLoc:
146 * @size: an int specifying the size in byte to allocate.
147 * @file: the file name or NULL
148 * @line: the line number
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 *
Daniel Veillard8599e702001-07-17 21:38:51 +0000156xmlMallocLoc(size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000157{
158 MEMHDR *p;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000159 void *ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000160
161 if (!xmlMemInitialized) xmlInitMemory();
162#ifdef DEBUG_MEMORY
163 xmlGenericError(xmlGenericErrorContext,
164 "Malloc(%d)\n",size);
165#endif
166
167 TEST_POINT
168
169 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
170
171 if (!p) {
172 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000173 "xmlMallocLoc : Out of free space\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000174 xmlMemoryDump();
175 return(NULL);
176 }
177 p->mh_tag = MEMTAG;
178 p->mh_number = ++block;
179 p->mh_size = size;
180 p->mh_type = MALLOC_TYPE;
181 p->mh_file = file;
182 p->mh_line = line;
183 debugMemSize += size;
184 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
185#ifdef MEM_LIST
186 debugmem_list_add(p);
187#endif
188
189#ifdef DEBUG_MEMORY
190 xmlGenericError(xmlGenericErrorContext,
191 "Malloc(%d) Ok\n",size);
192#endif
193
194 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
195
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000196 ret = HDR_2_CLIENT(p);
197
198 if (xmlMemTraceBlockAt == ret) {
199 xmlGenericError(xmlGenericErrorContext,
200 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
201 xmlMallocBreakpoint();
202 }
203
Owen Taylor3473f882001-02-23 17:55:21 +0000204 TEST_POINT
205
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000206 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000207}
208
209/**
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000210 * xmlMallocAtomicLoc:
211 * @size: an int specifying the size in byte to allocate.
212 * @file: the file name or NULL
213 * @line: the line number
214 *
215 * a malloc() equivalent, with logging of the allocation info.
216 *
217 * Returns a pointer to the allocated area or NULL in case of lack of memory.
218 */
219
220void *
221xmlMallocAtomicLoc(size_t size, const char * file, int line)
222{
223 MEMHDR *p;
224 void *ret;
225
226 if (!xmlMemInitialized) xmlInitMemory();
227#ifdef DEBUG_MEMORY
228 xmlGenericError(xmlGenericErrorContext,
229 "Malloc(%d)\n",size);
230#endif
231
232 TEST_POINT
233
234 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
235
236 if (!p) {
237 xmlGenericError(xmlGenericErrorContext,
238 "xmlMallocLoc : Out of free space\n");
239 xmlMemoryDump();
240 return(NULL);
241 }
242 p->mh_tag = MEMTAG;
243 p->mh_number = ++block;
244 p->mh_size = size;
245 p->mh_type = MALLOC_ATOMIC_TYPE;
246 p->mh_file = file;
247 p->mh_line = line;
248 debugMemSize += size;
249 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
250#ifdef MEM_LIST
251 debugmem_list_add(p);
252#endif
253
254#ifdef DEBUG_MEMORY
255 xmlGenericError(xmlGenericErrorContext,
256 "Malloc(%d) Ok\n",size);
257#endif
258
259 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
260
261 ret = HDR_2_CLIENT(p);
262
263 if (xmlMemTraceBlockAt == ret) {
264 xmlGenericError(xmlGenericErrorContext,
265 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
266 xmlMallocBreakpoint();
267 }
268
269 TEST_POINT
270
271 return(ret);
272}
273/**
Owen Taylor3473f882001-02-23 17:55:21 +0000274 * xmlMemMalloc:
275 * @size: an int specifying the size in byte to allocate.
276 *
277 * a malloc() equivalent, with logging of the allocation info.
278 *
279 * Returns a pointer to the allocated area or NULL in case of lack of memory.
280 */
281
282void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000283xmlMemMalloc(size_t size)
Owen Taylor3473f882001-02-23 17:55:21 +0000284{
285 return(xmlMallocLoc(size, "none", 0));
286}
287
288/**
289 * xmlReallocLoc:
290 * @ptr: the initial memory block pointer
291 * @size: an int specifying the size in byte to allocate.
292 * @file: the file name or NULL
293 * @line: the line number
294 *
295 * a realloc() equivalent, with logging of the allocation info.
296 *
297 * Returns a pointer to the allocated area or NULL in case of lack of memory.
298 */
299
300void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000301xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000302{
303 MEMHDR *p;
304 unsigned long number;
305
306 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000307 if (ptr == NULL)
308 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000309 TEST_POINT
310
311 p = CLIENT_2_HDR(ptr);
312 number = p->mh_number;
313 if (p->mh_tag != MEMTAG) {
314 Mem_Tag_Err(p);
315 goto error;
316 }
317 p->mh_tag = ~MEMTAG;
318 debugMemSize -= p->mh_size;
319#ifdef MEM_LIST
320 debugmem_list_delete(p);
321#endif
322
323 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
324 if (!p) {
325 goto error;
326 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000327 if (xmlMemTraceBlockAt == ptr) {
328 xmlGenericError(xmlGenericErrorContext,
329 "%p : Realloced(%d -> %d) Ok\n",
330 xmlMemTraceBlockAt, p->mh_size, size);
331 xmlMallocBreakpoint();
332 }
Owen Taylor3473f882001-02-23 17:55:21 +0000333 p->mh_tag = MEMTAG;
334 p->mh_number = number;
335 p->mh_type = REALLOC_TYPE;
336 p->mh_size = size;
337 p->mh_file = file;
338 p->mh_line = line;
339 debugMemSize += size;
340 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
341#ifdef MEM_LIST
342 debugmem_list_add(p);
343#endif
344
345 TEST_POINT
346
347 return(HDR_2_CLIENT(p));
348
349error:
350 return(NULL);
351}
352
353/**
354 * xmlMemRealloc:
355 * @ptr: the initial memory block pointer
356 * @size: an int specifying the size in byte to allocate.
357 *
358 * a realloc() equivalent, with logging of the allocation info.
359 *
360 * Returns a pointer to the allocated area or NULL in case of lack of memory.
361 */
362
363void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000364xmlMemRealloc(void *ptr,size_t size) {
Owen Taylor3473f882001-02-23 17:55:21 +0000365 return(xmlReallocLoc(ptr, size, "none", 0));
366}
367
368/**
369 * xmlMemFree:
370 * @ptr: the memory block pointer
371 *
372 * a free() equivalent, with error checking.
373 */
374void
375xmlMemFree(void *ptr)
376{
377 MEMHDR *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000378 char *target;
Owen Taylor3473f882001-02-23 17:55:21 +0000379
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000380 if (ptr == (void *) -1) {
381 xmlGenericError(xmlGenericErrorContext,
382 "trying to free pointer from freed area\n");
383 goto error;
384 }
385
386 if (xmlMemTraceBlockAt == ptr) {
387 xmlGenericError(xmlGenericErrorContext,
388 "%p : Freed()\n", xmlMemTraceBlockAt);
389 xmlMallocBreakpoint();
390 }
391
Owen Taylor3473f882001-02-23 17:55:21 +0000392 TEST_POINT
393
Daniel Veillard92ad2102001-03-27 12:47:33 +0000394 target = (char *) ptr;
395
Owen Taylor3473f882001-02-23 17:55:21 +0000396 p = CLIENT_2_HDR(ptr);
397 if (p->mh_tag != MEMTAG) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000398 Mem_Tag_Err(p);
399 goto error;
Owen Taylor3473f882001-02-23 17:55:21 +0000400 }
401 p->mh_tag = ~MEMTAG;
402 debugMemSize -= p->mh_size;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000403 memset(target, -1, p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000404
405#ifdef MEM_LIST
406 debugmem_list_delete(p);
407#endif
408 free(p);
409
410 TEST_POINT
411
412 return;
413
414error:
415 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000416 "xmlMemFree(%lX) error\n", (unsigned long) ptr);
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000417 xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000418 return;
419}
420
421/**
422 * xmlMemStrdupLoc:
Daniel Veillard9d06d302002-01-22 18:15:52 +0000423 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000424 * @file: the file name or NULL
425 * @line: the line number
426 *
427 * a strdup() equivalent, with logging of the allocation info.
428 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000429 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000430 */
431
432char *
433xmlMemStrdupLoc(const char *str, const char *file, int line)
434{
435 char *s;
436 size_t size = strlen(str) + 1;
437 MEMHDR *p;
438
439 if (!xmlMemInitialized) xmlInitMemory();
440 TEST_POINT
441
442 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
443 if (!p) {
444 goto error;
445 }
446 p->mh_tag = MEMTAG;
447 p->mh_number = ++block;
448 p->mh_size = size;
449 p->mh_type = STRDUP_TYPE;
450 p->mh_file = file;
451 p->mh_line = line;
452 debugMemSize += size;
453 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
454#ifdef MEM_LIST
455 debugmem_list_add(p);
456#endif
457 s = (char *) HDR_2_CLIENT(p);
458
459 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
460
461 if (s != NULL)
462 strcpy(s,str);
463 else
464 goto error;
465
466 TEST_POINT
467
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000468 if (xmlMemTraceBlockAt == s) {
469 xmlGenericError(xmlGenericErrorContext,
470 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
471 xmlMallocBreakpoint();
472 }
473
Owen Taylor3473f882001-02-23 17:55:21 +0000474 return(s);
475
476error:
477 return(NULL);
478}
479
480/**
481 * xmlMemoryStrdup:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000482 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000483 *
484 * a strdup() equivalent, with logging of the allocation info.
485 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000486 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000487 */
488
489char *
490xmlMemoryStrdup(const char *str) {
491 return(xmlMemStrdupLoc(str, "none", 0));
492}
493
494/**
495 * xmlMemUsed:
496 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000497 * Provides the amount of memory currently allocated
Owen Taylor3473f882001-02-23 17:55:21 +0000498 *
499 * Returns an int representing the amount of memory allocated.
500 */
501
502int
503xmlMemUsed(void) {
504 return(debugMemSize);
505}
506
507#ifdef MEM_LIST
508/**
509 * xmlMemContentShow:
510 * @fp: a FILE descriptor used as the output file
511 * @p: a memory block header
512 *
513 * tries to show some content from the memory block
514 */
515
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000516static void
Owen Taylor3473f882001-02-23 17:55:21 +0000517xmlMemContentShow(FILE *fp, MEMHDR *p)
518{
519 int i,j,len = p->mh_size;
520 const char *buf = (const char *) HDR_2_CLIENT(p);
521
522 if (p == NULL) {
523 fprintf(fp, " NULL");
524 return;
525 }
526
527 for (i = 0;i < len;i++) {
528 if (buf[i] == 0) break;
Daniel Veillard9f28f302002-02-15 20:48:08 +0000529 if (!isprint((unsigned char) buf[i])) break;
Owen Taylor3473f882001-02-23 17:55:21 +0000530 }
531 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
532 if (len >= 4) {
533 MEMHDR *q;
534 void *cur;
535
536 for (j = 0;j < len -3;j += 4) {
537 cur = *((void **) &buf[j]);
538 q = CLIENT_2_HDR(cur);
539 p = memlist;
540 while (p != NULL) {
541 if (p == q) break;
542 p = p->mh_next;
543 }
544 if ((p != NULL) && (p == q)) {
545 fprintf(fp, " pointer to #%lu at index %d",
546 p->mh_number, j);
547 return;
548 }
549 }
550 }
551 } else if ((i == 0) && (buf[i] == 0)) {
552 fprintf(fp," null");
553 } else {
554 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
555 else {
556 fprintf(fp," [");
557 for (j = 0;j < i;j++)
558 fprintf(fp,"%c", buf[j]);
559 fprintf(fp,"]");
560 }
561 }
562}
563#endif
564
565/**
566 * xmlMemShow:
567 * @fp: a FILE descriptor used as the output file
568 * @nr: number of entries to dump
569 *
570 * show a show display of the memory allocated, and dump
571 * the @nr last allocated areas which were not freed
572 */
573
574void
575xmlMemShow(FILE *fp, int nr)
576{
577#ifdef MEM_LIST
578 MEMHDR *p;
579#endif
580
581 if (fp != NULL)
582 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
583 debugMemSize, debugMaxMemSize);
584#ifdef MEM_LIST
585 if (nr > 0) {
586 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
587 p = memlist;
588 while ((p) && nr > 0) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000589 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000590 switch (p->mh_type) {
591 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
592 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000593 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000594 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000595 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
596 default:fprintf(fp," ??? in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000597 }
598 if (p->mh_file != NULL)
599 fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
600 if (p->mh_tag != MEMTAG)
601 fprintf(fp," INVALID");
602 xmlMemContentShow(fp, p);
603 fprintf(fp,"\n");
604 nr--;
605 p = p->mh_next;
606 }
607 }
608#endif /* MEM_LIST */
609}
610
611/**
612 * xmlMemDisplay:
613 * @fp: a FILE descriptor used as the output file, if NULL, the result is
614 * written to the file .memorylist
615 *
616 * show in-extenso the memory blocks allocated
617 */
618
619void
620xmlMemDisplay(FILE *fp)
621{
622#ifdef MEM_LIST
623 MEMHDR *p;
Daniel Veillard144024e2002-02-13 21:14:46 +0000624 unsigned idx;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000625 int nb = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000626#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
627 time_t currentTime;
628 char buf[500];
629 struct tm * tstruct;
630
631 currentTime = time(NULL);
632 tstruct = localtime(&currentTime);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000633 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
Owen Taylor3473f882001-02-23 17:55:21 +0000634 fprintf(fp," %s\n\n", buf);
635#endif
636
637
638 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
639 debugMemSize, debugMaxMemSize);
640 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
641 idx = 0;
642 p = memlist;
643 while (p) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000644 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
645 (unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000646 switch (p->mh_type) {
647 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
648 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
649 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000650 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
651 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000652 default:fprintf(fp," ??? in ");break;
653 }
654 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
655 if (p->mh_tag != MEMTAG)
656 fprintf(fp," INVALID");
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000657 nb++;
658 if (nb < 100)
659 xmlMemContentShow(fp, p);
660 else
661 fprintf(fp," skip");
662
Owen Taylor3473f882001-02-23 17:55:21 +0000663 fprintf(fp,"\n");
664 p = p->mh_next;
665 }
666#else
667 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
668#endif
669}
670
671#ifdef MEM_LIST
672
Daniel Veillard01c13b52002-12-10 15:19:08 +0000673static void debugmem_list_add(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000674{
675 p->mh_next = memlist;
676 p->mh_prev = NULL;
677 if (memlist) memlist->mh_prev = p;
678 memlist = p;
679#ifdef MEM_LIST_DEBUG
680 if (stderr)
681 Mem_Display(stderr);
682#endif
683}
684
Daniel Veillard01c13b52002-12-10 15:19:08 +0000685static void debugmem_list_delete(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000686{
687 if (p->mh_next)
688 p->mh_next->mh_prev = p->mh_prev;
689 if (p->mh_prev)
690 p->mh_prev->mh_next = p->mh_next;
691 else memlist = p->mh_next;
692#ifdef MEM_LIST_DEBUG
693 if (stderr)
694 Mem_Display(stderr);
695#endif
696}
697
698#endif
699
700/*
Daniel Veillard01c13b52002-12-10 15:19:08 +0000701 * debugmem_tag_error:
702 *
703 * internal error function.
Owen Taylor3473f882001-02-23 17:55:21 +0000704 */
705
Daniel Veillard01c13b52002-12-10 15:19:08 +0000706static void debugmem_tag_error(void *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000707{
708 xmlGenericError(xmlGenericErrorContext,
709 "Memory tag error occurs :%p \n\t bye\n", p);
710#ifdef MEM_LIST
711 if (stderr)
712 xmlMemDisplay(stderr);
713#endif
714}
715
Daniel Veillardb44025c2001-10-11 22:55:55 +0000716static FILE *xmlMemoryDumpFile = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000717
Daniel Veillard4432df22003-09-28 18:58:27 +0000718#endif /* DEBUG_MEMORY_LOCATION */
Owen Taylor3473f882001-02-23 17:55:21 +0000719
720/**
721 * xmlMemoryDump:
722 *
723 * Dump in-extenso the memory blocks allocated to the file .memorylist
724 */
725
726void
727xmlMemoryDump(void)
728{
Daniel Veillard4432df22003-09-28 18:58:27 +0000729#ifdef DEBUG_MEMORY_LOCATION
Owen Taylor3473f882001-02-23 17:55:21 +0000730 FILE *dump;
731
Daniel Veillard5997aca2002-03-18 18:36:20 +0000732 if (debugMaxMemSize == 0)
733 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000734 dump = fopen(".memdump", "w");
Daniel Veillardcd337f02001-11-22 18:20:37 +0000735 if (dump == NULL)
736 xmlMemoryDumpFile = stderr;
Owen Taylor3473f882001-02-23 17:55:21 +0000737 else xmlMemoryDumpFile = dump;
738
739 xmlMemDisplay(xmlMemoryDumpFile);
740
741 if (dump != NULL) fclose(dump);
Daniel Veillard4432df22003-09-28 18:58:27 +0000742#endif /* DEBUG_MEMORY_LOCATION */
Owen Taylor3473f882001-02-23 17:55:21 +0000743}
744
745
746/****************************************************************
747 * *
748 * Initialization Routines *
749 * *
750 ****************************************************************/
751
Daniel Veillard01c13b52002-12-10 15:19:08 +0000752static int xmlInitMemoryDone = 0;
753
Owen Taylor3473f882001-02-23 17:55:21 +0000754/**
755 * xmlInitMemory:
756 *
757 * Initialize the memory layer.
758 *
759 * Returns 0 on success
760 */
Owen Taylor3473f882001-02-23 17:55:21 +0000761int
762xmlInitMemory(void)
763{
Daniel Veillard4432df22003-09-28 18:58:27 +0000764#ifdef DEBUG_MEMORY_LOCATION
Owen Taylor3473f882001-02-23 17:55:21 +0000765#ifdef HAVE_STDLIB_H
766 char *breakpoint;
767#endif
Daniel Veillard4432df22003-09-28 18:58:27 +0000768#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000769
770 if (xmlInitMemoryDone) return(-1);
771
Daniel Veillard4432df22003-09-28 18:58:27 +0000772#ifdef DEBUG_MEMORY_LOCATION
Owen Taylor3473f882001-02-23 17:55:21 +0000773#ifdef HAVE_STDLIB_H
774 breakpoint = getenv("XML_MEM_BREAKPOINT");
775 if (breakpoint != NULL) {
776 sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
777 }
778#endif
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000779#ifdef HAVE_STDLIB_H
780 breakpoint = getenv("XML_MEM_TRACE");
781 if (breakpoint != NULL) {
782 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
783 }
784#endif
Daniel Veillard4432df22003-09-28 18:58:27 +0000785#endif /* DEBUG_MEMORY_LOCATION */
Owen Taylor3473f882001-02-23 17:55:21 +0000786
787#ifdef DEBUG_MEMORY
788 xmlGenericError(xmlGenericErrorContext,
789 "xmlInitMemory() Ok\n");
790#endif
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000791 xmlMemInitialized = 1;
792 xmlInitMemoryDone = 1;
793
Daniel Veillard4432df22003-09-28 18:58:27 +0000794 return(0);
Owen Taylor3473f882001-02-23 17:55:21 +0000795}
796
797/**
798 * xmlMemSetup:
799 * @freeFunc: the free() function to use
800 * @mallocFunc: the malloc() function to use
801 * @reallocFunc: the realloc() function to use
802 * @strdupFunc: the strdup() function to use
803 *
804 * Override the default memory access functions with a new set
805 * This has to be called before any other libxml routines !
806 *
807 * Should this be blocked if there was already some allocations
808 * done ?
809 *
810 * Returns 0 on success
811 */
812int
813xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
814 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
815 if (freeFunc == NULL)
816 return(-1);
817 if (mallocFunc == NULL)
818 return(-1);
819 if (reallocFunc == NULL)
820 return(-1);
821 if (strdupFunc == NULL)
822 return(-1);
823 xmlFree = freeFunc;
824 xmlMalloc = mallocFunc;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000825 xmlMallocAtomic = mallocFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000826 xmlRealloc = reallocFunc;
827 xmlMemStrdup = strdupFunc;
828 return(0);
829}
830
831/**
832 * xmlMemGet:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000833 * @freeFunc: place to save the free() function in use
834 * @mallocFunc: place to save the malloc() function in use
835 * @reallocFunc: place to save the realloc() function in use
836 * @strdupFunc: place to save the strdup() function in use
Owen Taylor3473f882001-02-23 17:55:21 +0000837 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000838 * Provides the memory access functions set currently in use
Owen Taylor3473f882001-02-23 17:55:21 +0000839 *
840 * Returns 0 on success
841 */
842int
843xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
844 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
845 if (freeFunc != NULL) *freeFunc = xmlFree;
846 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
847 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
848 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
849 return(0);
850}
851
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000852/**
853 * xmlGcMemSetup:
854 * @freeFunc: the free() function to use
855 * @mallocFunc: the malloc() function to use
856 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
857 * @reallocFunc: the realloc() function to use
858 * @strdupFunc: the strdup() function to use
859 *
860 * Override the default memory access functions with a new set
861 * This has to be called before any other libxml routines !
862 * The mallocAtomicFunc is specialized for atomic block
863 * allocations (i.e. of areas useful for garbage collected memory allocators
864 *
865 * Should this be blocked if there was already some allocations
866 * done ?
867 *
868 * Returns 0 on success
869 */
870int
871xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
872 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
873 xmlStrdupFunc strdupFunc) {
874 if (freeFunc == NULL)
875 return(-1);
876 if (mallocFunc == NULL)
877 return(-1);
878 if (mallocAtomicFunc == NULL)
879 return(-1);
880 if (reallocFunc == NULL)
881 return(-1);
882 if (strdupFunc == NULL)
883 return(-1);
884 xmlFree = freeFunc;
885 xmlMalloc = mallocFunc;
886 xmlMallocAtomic = mallocAtomicFunc;
887 xmlRealloc = reallocFunc;
888 xmlMemStrdup = strdupFunc;
889 return(0);
890}
891
892/**
893 * xmlGcMemGet:
894 * @freeFunc: place to save the free() function in use
895 * @mallocFunc: place to save the malloc() function in use
896 * @mallocAtomicFunc: place to save the atomic malloc() function in use
897 * @reallocFunc: place to save the realloc() function in use
898 * @strdupFunc: place to save the strdup() function in use
899 *
900 * Provides the memory access functions set currently in use
901 * The mallocAtomicFunc is specialized for atomic block
902 * allocations (i.e. of areas useful for garbage collected memory allocators
903 *
904 * Returns 0 on success
905 */
906int
907xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
908 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
909 xmlStrdupFunc *strdupFunc) {
910 if (freeFunc != NULL) *freeFunc = xmlFree;
911 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
912 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
913 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
914 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
915 return(0);
916}
917