blob: 38cb6599d1f8fc96365dd3557222cbc37ef82190 [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 Veillard8599e702001-07-17 21:38:51 +000047void * xmlMemMalloc(size_t size);
Daniel Veillard8599e702001-07-17 21:38:51 +000048void * xmlMemRealloc(void *ptr,size_t size);
Daniel Veillard56a4cb82001-03-24 17:00:36 +000049void xmlMemFree(void *ptr);
50char * xmlMemoryStrdup(const char *str);
51
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;
115static int xmlMemInitialized = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000116#ifdef MEM_LIST
117static MEMHDR *memlist = NULL;
118#endif
119
Daniel Veillard01c13b52002-12-10 15:19:08 +0000120static void debugmem_tag_error(void *addr);
Owen Taylor3473f882001-02-23 17:55:21 +0000121#ifdef MEM_LIST
Daniel Veillard01c13b52002-12-10 15:19:08 +0000122static void debugmem_list_add(MEMHDR *);
123static void debugmem_list_delete(MEMHDR *);
Owen Taylor3473f882001-02-23 17:55:21 +0000124#endif
125#define Mem_Tag_Err(a) debugmem_tag_error(a);
126
127#ifndef TEST_POINT
128#define TEST_POINT
129#endif
130
131/**
132 * xmlMallocBreakpoint:
133 *
134 * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
135 * number reaches the specified value this function is called. One need to add a breakpoint
136 * to it to get the context in which the given block is allocated.
137 */
138
139void
140xmlMallocBreakpoint(void) {
141 xmlGenericError(xmlGenericErrorContext,
142 "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
143}
144
145/**
146 * xmlMallocLoc:
147 * @size: an int specifying the size in byte to allocate.
148 * @file: the file name or NULL
149 * @line: the line number
150 *
151 * a malloc() equivalent, with logging of the allocation info.
152 *
153 * Returns a pointer to the allocated area or NULL in case of lack of memory.
154 */
155
156void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000157xmlMallocLoc(size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000158{
159 MEMHDR *p;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000160 void *ret;
Owen Taylor3473f882001-02-23 17:55:21 +0000161
162 if (!xmlMemInitialized) xmlInitMemory();
163#ifdef DEBUG_MEMORY
164 xmlGenericError(xmlGenericErrorContext,
165 "Malloc(%d)\n",size);
166#endif
167
168 TEST_POINT
169
170 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
171
172 if (!p) {
173 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000174 "xmlMallocLoc : Out of free space\n");
Owen Taylor3473f882001-02-23 17:55:21 +0000175 xmlMemoryDump();
176 return(NULL);
177 }
178 p->mh_tag = MEMTAG;
179 p->mh_number = ++block;
180 p->mh_size = size;
181 p->mh_type = MALLOC_TYPE;
182 p->mh_file = file;
183 p->mh_line = line;
184 debugMemSize += size;
185 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
186#ifdef MEM_LIST
187 debugmem_list_add(p);
188#endif
189
190#ifdef DEBUG_MEMORY
191 xmlGenericError(xmlGenericErrorContext,
192 "Malloc(%d) Ok\n",size);
193#endif
194
195 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
196
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000197 ret = HDR_2_CLIENT(p);
198
199 if (xmlMemTraceBlockAt == ret) {
200 xmlGenericError(xmlGenericErrorContext,
201 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
202 xmlMallocBreakpoint();
203 }
204
Owen Taylor3473f882001-02-23 17:55:21 +0000205 TEST_POINT
206
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000207 return(ret);
Owen Taylor3473f882001-02-23 17:55:21 +0000208}
209
210/**
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000211 * xmlMallocAtomicLoc:
212 * @size: an int specifying the size in byte to allocate.
213 * @file: the file name or NULL
214 * @line: the line number
215 *
216 * a malloc() equivalent, with logging of the allocation info.
217 *
218 * Returns a pointer to the allocated area or NULL in case of lack of memory.
219 */
220
221void *
222xmlMallocAtomicLoc(size_t size, const char * file, int line)
223{
224 MEMHDR *p;
225 void *ret;
226
227 if (!xmlMemInitialized) xmlInitMemory();
228#ifdef DEBUG_MEMORY
229 xmlGenericError(xmlGenericErrorContext,
230 "Malloc(%d)\n",size);
231#endif
232
233 TEST_POINT
234
235 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
236
237 if (!p) {
238 xmlGenericError(xmlGenericErrorContext,
239 "xmlMallocLoc : Out of free space\n");
240 xmlMemoryDump();
241 return(NULL);
242 }
243 p->mh_tag = MEMTAG;
244 p->mh_number = ++block;
245 p->mh_size = size;
246 p->mh_type = MALLOC_ATOMIC_TYPE;
247 p->mh_file = file;
248 p->mh_line = line;
249 debugMemSize += size;
250 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
251#ifdef MEM_LIST
252 debugmem_list_add(p);
253#endif
254
255#ifdef DEBUG_MEMORY
256 xmlGenericError(xmlGenericErrorContext,
257 "Malloc(%d) Ok\n",size);
258#endif
259
260 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
261
262 ret = HDR_2_CLIENT(p);
263
264 if (xmlMemTraceBlockAt == ret) {
265 xmlGenericError(xmlGenericErrorContext,
266 "%p : Malloc(%d) Ok\n", xmlMemTraceBlockAt, size);
267 xmlMallocBreakpoint();
268 }
269
270 TEST_POINT
271
272 return(ret);
273}
274/**
Owen Taylor3473f882001-02-23 17:55:21 +0000275 * xmlMemMalloc:
276 * @size: an int specifying the size in byte to allocate.
277 *
278 * a malloc() equivalent, with logging of the allocation info.
279 *
280 * Returns a pointer to the allocated area or NULL in case of lack of memory.
281 */
282
283void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000284xmlMemMalloc(size_t size)
Owen Taylor3473f882001-02-23 17:55:21 +0000285{
286 return(xmlMallocLoc(size, "none", 0));
287}
288
289/**
290 * xmlReallocLoc:
291 * @ptr: the initial memory block pointer
292 * @size: an int specifying the size in byte to allocate.
293 * @file: the file name or NULL
294 * @line: the line number
295 *
296 * a realloc() equivalent, with logging of the allocation info.
297 *
298 * Returns a pointer to the allocated area or NULL in case of lack of memory.
299 */
300
301void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000302xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
Owen Taylor3473f882001-02-23 17:55:21 +0000303{
304 MEMHDR *p;
305 unsigned long number;
306
307 if (!xmlMemInitialized) xmlInitMemory();
Daniel Veillarda76fe5c2003-04-24 16:06:47 +0000308 if (ptr == NULL)
309 return(NULL);
Owen Taylor3473f882001-02-23 17:55:21 +0000310 TEST_POINT
311
312 p = CLIENT_2_HDR(ptr);
313 number = p->mh_number;
314 if (p->mh_tag != MEMTAG) {
315 Mem_Tag_Err(p);
316 goto error;
317 }
318 p->mh_tag = ~MEMTAG;
319 debugMemSize -= p->mh_size;
320#ifdef MEM_LIST
321 debugmem_list_delete(p);
322#endif
323
324 p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
325 if (!p) {
326 goto error;
327 }
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000328 if (xmlMemTraceBlockAt == ptr) {
329 xmlGenericError(xmlGenericErrorContext,
330 "%p : Realloced(%d -> %d) Ok\n",
331 xmlMemTraceBlockAt, p->mh_size, size);
332 xmlMallocBreakpoint();
333 }
Owen Taylor3473f882001-02-23 17:55:21 +0000334 p->mh_tag = MEMTAG;
335 p->mh_number = number;
336 p->mh_type = REALLOC_TYPE;
337 p->mh_size = size;
338 p->mh_file = file;
339 p->mh_line = line;
340 debugMemSize += size;
341 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
342#ifdef MEM_LIST
343 debugmem_list_add(p);
344#endif
345
346 TEST_POINT
347
348 return(HDR_2_CLIENT(p));
349
350error:
351 return(NULL);
352}
353
354/**
355 * xmlMemRealloc:
356 * @ptr: the initial memory block pointer
357 * @size: an int specifying the size in byte to allocate.
358 *
359 * a realloc() equivalent, with logging of the allocation info.
360 *
361 * Returns a pointer to the allocated area or NULL in case of lack of memory.
362 */
363
364void *
Daniel Veillard8599e702001-07-17 21:38:51 +0000365xmlMemRealloc(void *ptr,size_t size) {
Owen Taylor3473f882001-02-23 17:55:21 +0000366 return(xmlReallocLoc(ptr, size, "none", 0));
367}
368
369/**
370 * xmlMemFree:
371 * @ptr: the memory block pointer
372 *
373 * a free() equivalent, with error checking.
374 */
375void
376xmlMemFree(void *ptr)
377{
378 MEMHDR *p;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000379 char *target;
Owen Taylor3473f882001-02-23 17:55:21 +0000380
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000381 if (ptr == (void *) -1) {
382 xmlGenericError(xmlGenericErrorContext,
383 "trying to free pointer from freed area\n");
384 goto error;
385 }
386
387 if (xmlMemTraceBlockAt == ptr) {
388 xmlGenericError(xmlGenericErrorContext,
389 "%p : Freed()\n", xmlMemTraceBlockAt);
390 xmlMallocBreakpoint();
391 }
392
Owen Taylor3473f882001-02-23 17:55:21 +0000393 TEST_POINT
394
Daniel Veillard92ad2102001-03-27 12:47:33 +0000395 target = (char *) ptr;
396
Owen Taylor3473f882001-02-23 17:55:21 +0000397 p = CLIENT_2_HDR(ptr);
398 if (p->mh_tag != MEMTAG) {
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000399 Mem_Tag_Err(p);
400 goto error;
Owen Taylor3473f882001-02-23 17:55:21 +0000401 }
402 p->mh_tag = ~MEMTAG;
403 debugMemSize -= p->mh_size;
Daniel Veillard92ad2102001-03-27 12:47:33 +0000404 memset(target, -1, p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000405
406#ifdef MEM_LIST
407 debugmem_list_delete(p);
408#endif
409 free(p);
410
411 TEST_POINT
412
413 return;
414
415error:
416 xmlGenericError(xmlGenericErrorContext,
Daniel Veillard26908ab2002-01-01 16:50:03 +0000417 "xmlMemFree(%lX) error\n", (unsigned long) ptr);
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000418 xmlMallocBreakpoint();
Owen Taylor3473f882001-02-23 17:55:21 +0000419 return;
420}
421
422/**
423 * xmlMemStrdupLoc:
Daniel Veillard9d06d302002-01-22 18:15:52 +0000424 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000425 * @file: the file name or NULL
426 * @line: the line number
427 *
428 * a strdup() equivalent, with logging of the allocation info.
429 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000430 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000431 */
432
433char *
434xmlMemStrdupLoc(const char *str, const char *file, int line)
435{
436 char *s;
437 size_t size = strlen(str) + 1;
438 MEMHDR *p;
439
440 if (!xmlMemInitialized) xmlInitMemory();
441 TEST_POINT
442
443 p = (MEMHDR *) malloc(RESERVE_SIZE+size);
444 if (!p) {
445 goto error;
446 }
447 p->mh_tag = MEMTAG;
448 p->mh_number = ++block;
449 p->mh_size = size;
450 p->mh_type = STRDUP_TYPE;
451 p->mh_file = file;
452 p->mh_line = line;
453 debugMemSize += size;
454 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
455#ifdef MEM_LIST
456 debugmem_list_add(p);
457#endif
458 s = (char *) HDR_2_CLIENT(p);
459
460 if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
461
462 if (s != NULL)
463 strcpy(s,str);
464 else
465 goto error;
466
467 TEST_POINT
468
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000469 if (xmlMemTraceBlockAt == s) {
470 xmlGenericError(xmlGenericErrorContext,
471 "%p : Strdup() Ok\n", xmlMemTraceBlockAt);
472 xmlMallocBreakpoint();
473 }
474
Owen Taylor3473f882001-02-23 17:55:21 +0000475 return(s);
476
477error:
478 return(NULL);
479}
480
481/**
482 * xmlMemoryStrdup:
Daniel Veillard01c13b52002-12-10 15:19:08 +0000483 * @str: the initial string pointer
Owen Taylor3473f882001-02-23 17:55:21 +0000484 *
485 * a strdup() equivalent, with logging of the allocation info.
486 *
Daniel Veillard26908ab2002-01-01 16:50:03 +0000487 * Returns a pointer to the new string or NULL if allocation error occurred.
Owen Taylor3473f882001-02-23 17:55:21 +0000488 */
489
490char *
491xmlMemoryStrdup(const char *str) {
492 return(xmlMemStrdupLoc(str, "none", 0));
493}
494
495/**
496 * xmlMemUsed:
497 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000498 * Provides the amount of memory currently allocated
Owen Taylor3473f882001-02-23 17:55:21 +0000499 *
500 * Returns an int representing the amount of memory allocated.
501 */
502
503int
504xmlMemUsed(void) {
505 return(debugMemSize);
506}
507
508#ifdef MEM_LIST
509/**
510 * xmlMemContentShow:
511 * @fp: a FILE descriptor used as the output file
512 * @p: a memory block header
513 *
514 * tries to show some content from the memory block
515 */
516
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000517static void
Owen Taylor3473f882001-02-23 17:55:21 +0000518xmlMemContentShow(FILE *fp, MEMHDR *p)
519{
520 int i,j,len = p->mh_size;
521 const char *buf = (const char *) HDR_2_CLIENT(p);
522
523 if (p == NULL) {
524 fprintf(fp, " NULL");
525 return;
526 }
527
528 for (i = 0;i < len;i++) {
529 if (buf[i] == 0) break;
Daniel Veillard9f28f302002-02-15 20:48:08 +0000530 if (!isprint((unsigned char) buf[i])) break;
Owen Taylor3473f882001-02-23 17:55:21 +0000531 }
532 if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
533 if (len >= 4) {
534 MEMHDR *q;
535 void *cur;
536
537 for (j = 0;j < len -3;j += 4) {
538 cur = *((void **) &buf[j]);
539 q = CLIENT_2_HDR(cur);
540 p = memlist;
541 while (p != NULL) {
542 if (p == q) break;
543 p = p->mh_next;
544 }
545 if ((p != NULL) && (p == q)) {
546 fprintf(fp, " pointer to #%lu at index %d",
547 p->mh_number, j);
548 return;
549 }
550 }
551 }
552 } else if ((i == 0) && (buf[i] == 0)) {
553 fprintf(fp," null");
554 } else {
555 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
556 else {
557 fprintf(fp," [");
558 for (j = 0;j < i;j++)
559 fprintf(fp,"%c", buf[j]);
560 fprintf(fp,"]");
561 }
562 }
563}
564#endif
565
566/**
567 * xmlMemShow:
568 * @fp: a FILE descriptor used as the output file
569 * @nr: number of entries to dump
570 *
571 * show a show display of the memory allocated, and dump
572 * the @nr last allocated areas which were not freed
573 */
574
575void
576xmlMemShow(FILE *fp, int nr)
577{
578#ifdef MEM_LIST
579 MEMHDR *p;
580#endif
581
582 if (fp != NULL)
583 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
584 debugMemSize, debugMaxMemSize);
585#ifdef MEM_LIST
586 if (nr > 0) {
587 fprintf(fp,"NUMBER SIZE TYPE WHERE\n");
588 p = memlist;
589 while ((p) && nr > 0) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000590 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000591 switch (p->mh_type) {
592 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
593 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000594 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000595 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000596 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
597 default:fprintf(fp," ??? in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000598 }
599 if (p->mh_file != NULL)
600 fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
601 if (p->mh_tag != MEMTAG)
602 fprintf(fp," INVALID");
603 xmlMemContentShow(fp, p);
604 fprintf(fp,"\n");
605 nr--;
606 p = p->mh_next;
607 }
608 }
609#endif /* MEM_LIST */
610}
611
612/**
613 * xmlMemDisplay:
614 * @fp: a FILE descriptor used as the output file, if NULL, the result is
615 * written to the file .memorylist
616 *
617 * show in-extenso the memory blocks allocated
618 */
619
620void
621xmlMemDisplay(FILE *fp)
622{
623#ifdef MEM_LIST
624 MEMHDR *p;
Daniel Veillard144024e2002-02-13 21:14:46 +0000625 unsigned idx;
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000626 int nb = 0;
Owen Taylor3473f882001-02-23 17:55:21 +0000627#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
628 time_t currentTime;
629 char buf[500];
630 struct tm * tstruct;
631
632 currentTime = time(NULL);
633 tstruct = localtime(&currentTime);
Daniel Veillard56a4cb82001-03-24 17:00:36 +0000634 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
Owen Taylor3473f882001-02-23 17:55:21 +0000635 fprintf(fp," %s\n\n", buf);
636#endif
637
638
639 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n",
640 debugMemSize, debugMaxMemSize);
641 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n");
642 idx = 0;
643 p = memlist;
644 while (p) {
Daniel Veillard144024e2002-02-13 21:14:46 +0000645 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number,
646 (unsigned long)p->mh_size);
Owen Taylor3473f882001-02-23 17:55:21 +0000647 switch (p->mh_type) {
648 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break;
649 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break;
650 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000651 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break;
652 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
Owen Taylor3473f882001-02-23 17:55:21 +0000653 default:fprintf(fp," ??? in ");break;
654 }
655 if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
656 if (p->mh_tag != MEMTAG)
657 fprintf(fp," INVALID");
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000658 nb++;
659 if (nb < 100)
660 xmlMemContentShow(fp, p);
661 else
662 fprintf(fp," skip");
663
Owen Taylor3473f882001-02-23 17:55:21 +0000664 fprintf(fp,"\n");
665 p = p->mh_next;
666 }
667#else
668 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
669#endif
670}
671
672#ifdef MEM_LIST
673
Daniel Veillard01c13b52002-12-10 15:19:08 +0000674static void debugmem_list_add(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000675{
676 p->mh_next = memlist;
677 p->mh_prev = NULL;
678 if (memlist) memlist->mh_prev = p;
679 memlist = p;
680#ifdef MEM_LIST_DEBUG
681 if (stderr)
682 Mem_Display(stderr);
683#endif
684}
685
Daniel Veillard01c13b52002-12-10 15:19:08 +0000686static void debugmem_list_delete(MEMHDR *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000687{
688 if (p->mh_next)
689 p->mh_next->mh_prev = p->mh_prev;
690 if (p->mh_prev)
691 p->mh_prev->mh_next = p->mh_next;
692 else memlist = p->mh_next;
693#ifdef MEM_LIST_DEBUG
694 if (stderr)
695 Mem_Display(stderr);
696#endif
697}
698
699#endif
700
701/*
Daniel Veillard01c13b52002-12-10 15:19:08 +0000702 * debugmem_tag_error:
703 *
704 * internal error function.
Owen Taylor3473f882001-02-23 17:55:21 +0000705 */
706
Daniel Veillard01c13b52002-12-10 15:19:08 +0000707static void debugmem_tag_error(void *p)
Owen Taylor3473f882001-02-23 17:55:21 +0000708{
709 xmlGenericError(xmlGenericErrorContext,
710 "Memory tag error occurs :%p \n\t bye\n", p);
711#ifdef MEM_LIST
712 if (stderr)
713 xmlMemDisplay(stderr);
714#endif
715}
716
Daniel Veillardb44025c2001-10-11 22:55:55 +0000717static FILE *xmlMemoryDumpFile = NULL;
Owen Taylor3473f882001-02-23 17:55:21 +0000718
719
720/**
721 * xmlMemoryDump:
722 *
723 * Dump in-extenso the memory blocks allocated to the file .memorylist
724 */
725
726void
727xmlMemoryDump(void)
728{
Owen Taylor3473f882001-02-23 17:55:21 +0000729 FILE *dump;
730
Daniel Veillard5997aca2002-03-18 18:36:20 +0000731 if (debugMaxMemSize == 0)
732 return;
Owen Taylor3473f882001-02-23 17:55:21 +0000733 dump = fopen(".memdump", "w");
Daniel Veillardcd337f02001-11-22 18:20:37 +0000734 if (dump == NULL)
735 xmlMemoryDumpFile = stderr;
Owen Taylor3473f882001-02-23 17:55:21 +0000736 else xmlMemoryDumpFile = dump;
737
738 xmlMemDisplay(xmlMemoryDumpFile);
739
740 if (dump != NULL) fclose(dump);
Owen Taylor3473f882001-02-23 17:55:21 +0000741}
742
743
744/****************************************************************
745 * *
746 * Initialization Routines *
747 * *
748 ****************************************************************/
749
Daniel Veillard01c13b52002-12-10 15:19:08 +0000750static int xmlInitMemoryDone = 0;
751
Owen Taylor3473f882001-02-23 17:55:21 +0000752/**
753 * xmlInitMemory:
754 *
755 * Initialize the memory layer.
756 *
757 * Returns 0 on success
758 */
Owen Taylor3473f882001-02-23 17:55:21 +0000759int
760xmlInitMemory(void)
761{
762 int ret;
763
764#ifdef HAVE_STDLIB_H
765 char *breakpoint;
766#endif
767
768 if (xmlInitMemoryDone) return(-1);
769
770#ifdef HAVE_STDLIB_H
771 breakpoint = getenv("XML_MEM_BREAKPOINT");
772 if (breakpoint != NULL) {
773 sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
774 }
775#endif
Daniel Veillard7d7e3792001-07-30 13:42:13 +0000776#ifdef HAVE_STDLIB_H
777 breakpoint = getenv("XML_MEM_TRACE");
778 if (breakpoint != NULL) {
779 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
780 }
781#endif
Owen Taylor3473f882001-02-23 17:55:21 +0000782
783#ifdef DEBUG_MEMORY
784 xmlGenericError(xmlGenericErrorContext,
785 "xmlInitMemory() Ok\n");
786#endif
Daniel Veillardd30be4a2002-03-28 18:25:31 +0000787 xmlMemInitialized = 1;
788 xmlInitMemoryDone = 1;
789
Owen Taylor3473f882001-02-23 17:55:21 +0000790 ret = 0;
791 return(ret);
792}
793
794/**
795 * xmlMemSetup:
796 * @freeFunc: the free() function to use
797 * @mallocFunc: the malloc() function to use
798 * @reallocFunc: the realloc() function to use
799 * @strdupFunc: the strdup() function to use
800 *
801 * Override the default memory access functions with a new set
802 * This has to be called before any other libxml routines !
803 *
804 * Should this be blocked if there was already some allocations
805 * done ?
806 *
807 * Returns 0 on success
808 */
809int
810xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
811 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
812 if (freeFunc == NULL)
813 return(-1);
814 if (mallocFunc == NULL)
815 return(-1);
816 if (reallocFunc == NULL)
817 return(-1);
818 if (strdupFunc == NULL)
819 return(-1);
820 xmlFree = freeFunc;
821 xmlMalloc = mallocFunc;
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000822 xmlMallocAtomic = mallocFunc;
Owen Taylor3473f882001-02-23 17:55:21 +0000823 xmlRealloc = reallocFunc;
824 xmlMemStrdup = strdupFunc;
825 return(0);
826}
827
828/**
829 * xmlMemGet:
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000830 * @freeFunc: place to save the free() function in use
831 * @mallocFunc: place to save the malloc() function in use
832 * @reallocFunc: place to save the realloc() function in use
833 * @strdupFunc: place to save the strdup() function in use
Owen Taylor3473f882001-02-23 17:55:21 +0000834 *
Daniel Veillarda9b66d02002-12-11 14:23:49 +0000835 * Provides the memory access functions set currently in use
Owen Taylor3473f882001-02-23 17:55:21 +0000836 *
837 * Returns 0 on success
838 */
839int
840xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
841 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
842 if (freeFunc != NULL) *freeFunc = xmlFree;
843 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
844 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
845 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
846 return(0);
847}
848
Daniel Veillard3c908dc2003-04-19 00:07:51 +0000849/**
850 * xmlGcMemSetup:
851 * @freeFunc: the free() function to use
852 * @mallocFunc: the malloc() function to use
853 * @mallocAtomicFunc: the malloc() function to use for atomic allocations
854 * @reallocFunc: the realloc() function to use
855 * @strdupFunc: the strdup() function to use
856 *
857 * Override the default memory access functions with a new set
858 * This has to be called before any other libxml routines !
859 * The mallocAtomicFunc is specialized for atomic block
860 * allocations (i.e. of areas useful for garbage collected memory allocators
861 *
862 * Should this be blocked if there was already some allocations
863 * done ?
864 *
865 * Returns 0 on success
866 */
867int
868xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
869 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
870 xmlStrdupFunc strdupFunc) {
871 if (freeFunc == NULL)
872 return(-1);
873 if (mallocFunc == NULL)
874 return(-1);
875 if (mallocAtomicFunc == NULL)
876 return(-1);
877 if (reallocFunc == NULL)
878 return(-1);
879 if (strdupFunc == NULL)
880 return(-1);
881 xmlFree = freeFunc;
882 xmlMalloc = mallocFunc;
883 xmlMallocAtomic = mallocAtomicFunc;
884 xmlRealloc = reallocFunc;
885 xmlMemStrdup = strdupFunc;
886 return(0);
887}
888
889/**
890 * xmlGcMemGet:
891 * @freeFunc: place to save the free() function in use
892 * @mallocFunc: place to save the malloc() function in use
893 * @mallocAtomicFunc: place to save the atomic malloc() function in use
894 * @reallocFunc: place to save the realloc() function in use
895 * @strdupFunc: place to save the strdup() function in use
896 *
897 * Provides the memory access functions set currently in use
898 * The mallocAtomicFunc is specialized for atomic block
899 * allocations (i.e. of areas useful for garbage collected memory allocators
900 *
901 * Returns 0 on success
902 */
903int
904xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
905 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
906 xmlStrdupFunc *strdupFunc) {
907 if (freeFunc != NULL) *freeFunc = xmlFree;
908 if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
909 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
910 if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
911 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
912 return(0);
913}
914