Home | History | Annotate | Download | only in libxml2
      1 /*
      2  * xmlmemory.c:  libxml memory allocator wrapper.
      3  *
      4  * daniel (at) veillard.com
      5  */
      6 
      7 #define IN_LIBXML
      8 #include "libxml.h"
      9 
     10 #include <string.h>
     11 
     12 #ifdef HAVE_SYS_TYPES_H
     13 #include <sys/types.h>
     14 #endif
     15 
     16 #ifdef HAVE_TIME_H
     17 #include <time.h>
     18 #endif
     19 
     20 #ifdef HAVE_STDLIB_H
     21 #include <stdlib.h>
     22 #else
     23 #ifdef HAVE_MALLOC_H
     24 #include <malloc.h>
     25 #endif
     26 #endif
     27 
     28 #ifdef HAVE_CTYPE_H
     29 #include <ctype.h>
     30 #endif
     31 
     32 /* #define DEBUG_MEMORY */
     33 
     34 /**
     35  * MEM_LIST:
     36  *
     37  * keep track of all allocated blocks for error reporting
     38  * Always build the memory list !
     39  */
     40 #ifdef DEBUG_MEMORY_LOCATION
     41 #ifndef MEM_LIST
     42 #define MEM_LIST /* keep a list of all the allocated memory blocks */
     43 #endif
     44 #endif
     45 
     46 #include <libxml/globals.h>	/* must come before xmlmemory.h */
     47 #include <libxml/xmlmemory.h>
     48 #include <libxml/xmlerror.h>
     49 #include <libxml/threads.h>
     50 
     51 static int xmlMemInitialized = 0;
     52 static unsigned long  debugMemSize = 0;
     53 static unsigned long  debugMemBlocks = 0;
     54 static unsigned long  debugMaxMemSize = 0;
     55 static xmlMutexPtr xmlMemMutex = NULL;
     56 
     57 void xmlMallocBreakpoint(void);
     58 
     59 /************************************************************************
     60  *									*
     61  *		Macros, variables and associated types			*
     62  *									*
     63  ************************************************************************/
     64 
     65 #if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
     66 #ifdef xmlMalloc
     67 #undef xmlMalloc
     68 #endif
     69 #ifdef xmlRealloc
     70 #undef xmlRealloc
     71 #endif
     72 #ifdef xmlMemStrdup
     73 #undef xmlMemStrdup
     74 #endif
     75 #endif
     76 
     77 /*
     78  * Each of the blocks allocated begin with a header containing informations
     79  */
     80 
     81 #define MEMTAG 0x5aa5
     82 
     83 #define MALLOC_TYPE 1
     84 #define REALLOC_TYPE 2
     85 #define STRDUP_TYPE 3
     86 #define MALLOC_ATOMIC_TYPE 4
     87 #define REALLOC_ATOMIC_TYPE 5
     88 
     89 typedef struct memnod {
     90     unsigned int   mh_tag;
     91     unsigned int   mh_type;
     92     unsigned long  mh_number;
     93     size_t         mh_size;
     94 #ifdef MEM_LIST
     95    struct memnod *mh_next;
     96    struct memnod *mh_prev;
     97 #endif
     98    const char    *mh_file;
     99    unsigned int   mh_line;
    100 }  MEMHDR;
    101 
    102 
    103 #ifdef SUN4
    104 #define ALIGN_SIZE  16
    105 #else
    106 #define ALIGN_SIZE  sizeof(double)
    107 #endif
    108 #define HDR_SIZE    sizeof(MEMHDR)
    109 #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
    110 		      / ALIGN_SIZE ) * ALIGN_SIZE)
    111 
    112 
    113 #define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
    114 #define HDR_2_CLIENT(a)    ((void *) (((char *) (a)) + RESERVE_SIZE))
    115 
    116 
    117 static unsigned int block=0;
    118 static unsigned int xmlMemStopAtBlock = 0;
    119 static void *xmlMemTraceBlockAt = NULL;
    120 #ifdef MEM_LIST
    121 static MEMHDR *memlist = NULL;
    122 #endif
    123 
    124 static void debugmem_tag_error(void *addr);
    125 #ifdef MEM_LIST
    126 static void  debugmem_list_add(MEMHDR *);
    127 static void debugmem_list_delete(MEMHDR *);
    128 #endif
    129 #define Mem_Tag_Err(a) debugmem_tag_error(a);
    130 
    131 #ifndef TEST_POINT
    132 #define TEST_POINT
    133 #endif
    134 
    135 /**
    136  * xmlMallocBreakpoint:
    137  *
    138  * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
    139  * number reaches the specified value this function is called. One need to add a breakpoint
    140  * to it to get the context in which the given block is allocated.
    141  */
    142 
    143 void
    144 xmlMallocBreakpoint(void) {
    145     xmlGenericError(xmlGenericErrorContext,
    146 	    "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
    147 }
    148 
    149 /**
    150  * xmlMallocLoc:
    151  * @size:  an int specifying the size in byte to allocate.
    152  * @file:  the file name or NULL
    153  * @line:  the line number
    154  *
    155  * a malloc() equivalent, with logging of the allocation info.
    156  *
    157  * Returns a pointer to the allocated area or NULL in case of lack of memory.
    158  */
    159 
    160 void *
    161 xmlMallocLoc(size_t size, const char * file, int line)
    162 {
    163     MEMHDR *p;
    164     void *ret;
    165 
    166     if (!xmlMemInitialized) xmlInitMemory();
    167 #ifdef DEBUG_MEMORY
    168     xmlGenericError(xmlGenericErrorContext,
    169 	    "Malloc(%d)\n",size);
    170 #endif
    171 
    172     TEST_POINT
    173 
    174     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
    175 
    176     if (!p) {
    177 	xmlGenericError(xmlGenericErrorContext,
    178 		"xmlMallocLoc : Out of free space\n");
    179 	xmlMemoryDump();
    180 	return(NULL);
    181     }
    182     p->mh_tag = MEMTAG;
    183     p->mh_size = size;
    184     p->mh_type = MALLOC_TYPE;
    185     p->mh_file = file;
    186     p->mh_line = line;
    187     xmlMutexLock(xmlMemMutex);
    188     p->mh_number = ++block;
    189     debugMemSize += size;
    190     debugMemBlocks++;
    191     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
    192 #ifdef MEM_LIST
    193     debugmem_list_add(p);
    194 #endif
    195     xmlMutexUnlock(xmlMemMutex);
    196 
    197 #ifdef DEBUG_MEMORY
    198     xmlGenericError(xmlGenericErrorContext,
    199 	    "Malloc(%d) Ok\n",size);
    200 #endif
    201 
    202     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
    203 
    204     ret = HDR_2_CLIENT(p);
    205 
    206     if (xmlMemTraceBlockAt == ret) {
    207 	xmlGenericError(xmlGenericErrorContext,
    208 			"%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
    209 			(long unsigned)size);
    210 	xmlMallocBreakpoint();
    211     }
    212 
    213     TEST_POINT
    214 
    215     return(ret);
    216 }
    217 
    218 /**
    219  * xmlMallocAtomicLoc:
    220  * @size:  an int specifying the size in byte to allocate.
    221  * @file:  the file name or NULL
    222  * @line:  the line number
    223  *
    224  * a malloc() equivalent, with logging of the allocation info.
    225  *
    226  * Returns a pointer to the allocated area or NULL in case of lack of memory.
    227  */
    228 
    229 void *
    230 xmlMallocAtomicLoc(size_t size, const char * file, int line)
    231 {
    232     MEMHDR *p;
    233     void *ret;
    234 
    235     if (!xmlMemInitialized) xmlInitMemory();
    236 #ifdef DEBUG_MEMORY
    237     xmlGenericError(xmlGenericErrorContext,
    238 	    "Malloc(%d)\n",size);
    239 #endif
    240 
    241     TEST_POINT
    242 
    243     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
    244 
    245     if (!p) {
    246 	xmlGenericError(xmlGenericErrorContext,
    247 		"xmlMallocLoc : Out of free space\n");
    248 	xmlMemoryDump();
    249 	return(NULL);
    250     }
    251     p->mh_tag = MEMTAG;
    252     p->mh_size = size;
    253     p->mh_type = MALLOC_ATOMIC_TYPE;
    254     p->mh_file = file;
    255     p->mh_line = line;
    256     xmlMutexLock(xmlMemMutex);
    257     p->mh_number = ++block;
    258     debugMemSize += size;
    259     debugMemBlocks++;
    260     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
    261 #ifdef MEM_LIST
    262     debugmem_list_add(p);
    263 #endif
    264     xmlMutexUnlock(xmlMemMutex);
    265 
    266 #ifdef DEBUG_MEMORY
    267     xmlGenericError(xmlGenericErrorContext,
    268 	    "Malloc(%d) Ok\n",size);
    269 #endif
    270 
    271     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
    272 
    273     ret = HDR_2_CLIENT(p);
    274 
    275     if (xmlMemTraceBlockAt == ret) {
    276 	xmlGenericError(xmlGenericErrorContext,
    277 			"%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt,
    278 			(long unsigned)size);
    279 	xmlMallocBreakpoint();
    280     }
    281 
    282     TEST_POINT
    283 
    284     return(ret);
    285 }
    286 /**
    287  * xmlMemMalloc:
    288  * @size:  an int specifying the size in byte to allocate.
    289  *
    290  * a malloc() equivalent, with logging of the allocation info.
    291  *
    292  * Returns a pointer to the allocated area or NULL in case of lack of memory.
    293  */
    294 
    295 void *
    296 xmlMemMalloc(size_t size)
    297 {
    298     return(xmlMallocLoc(size, "none", 0));
    299 }
    300 
    301 /**
    302  * xmlReallocLoc:
    303  * @ptr:  the initial memory block pointer
    304  * @size:  an int specifying the size in byte to allocate.
    305  * @file:  the file name or NULL
    306  * @line:  the line number
    307  *
    308  * a realloc() equivalent, with logging of the allocation info.
    309  *
    310  * Returns a pointer to the allocated area or NULL in case of lack of memory.
    311  */
    312 
    313 void *
    314 xmlReallocLoc(void *ptr,size_t size, const char * file, int line)
    315 {
    316     MEMHDR *p, *tmp;
    317     unsigned long number;
    318 #ifdef DEBUG_MEMORY
    319     size_t oldsize;
    320 #endif
    321 
    322     if (ptr == NULL)
    323         return(xmlMallocLoc(size, file, line));
    324 
    325     if (!xmlMemInitialized) xmlInitMemory();
    326     TEST_POINT
    327 
    328     p = CLIENT_2_HDR(ptr);
    329     number = p->mh_number;
    330     if (xmlMemStopAtBlock == number) xmlMallocBreakpoint();
    331     if (p->mh_tag != MEMTAG) {
    332        Mem_Tag_Err(p);
    333 	 goto error;
    334     }
    335     p->mh_tag = ~MEMTAG;
    336     xmlMutexLock(xmlMemMutex);
    337     debugMemSize -= p->mh_size;
    338     debugMemBlocks--;
    339 #ifdef DEBUG_MEMORY
    340     oldsize = p->mh_size;
    341 #endif
    342 #ifdef MEM_LIST
    343     debugmem_list_delete(p);
    344 #endif
    345     xmlMutexUnlock(xmlMemMutex);
    346 
    347     tmp = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
    348     if (!tmp) {
    349 	 free(p);
    350 	 goto error;
    351     }
    352     p = tmp;
    353     if (xmlMemTraceBlockAt == ptr) {
    354 	xmlGenericError(xmlGenericErrorContext,
    355 			"%p : Realloced(%lu -> %lu) Ok\n",
    356 			xmlMemTraceBlockAt, (long unsigned)p->mh_size,
    357 			(long unsigned)size);
    358 	xmlMallocBreakpoint();
    359     }
    360     p->mh_tag = MEMTAG;
    361     p->mh_number = number;
    362     p->mh_type = REALLOC_TYPE;
    363     p->mh_size = size;
    364     p->mh_file = file;
    365     p->mh_line = line;
    366     xmlMutexLock(xmlMemMutex);
    367     debugMemSize += size;
    368     debugMemBlocks++;
    369     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
    370 #ifdef MEM_LIST
    371     debugmem_list_add(p);
    372 #endif
    373     xmlMutexUnlock(xmlMemMutex);
    374 
    375     TEST_POINT
    376 
    377 #ifdef DEBUG_MEMORY
    378     xmlGenericError(xmlGenericErrorContext,
    379 	    "Realloced(%d to %d) Ok\n", oldsize, size);
    380 #endif
    381     return(HDR_2_CLIENT(p));
    382 
    383 error:
    384     return(NULL);
    385 }
    386 
    387 /**
    388  * xmlMemRealloc:
    389  * @ptr:  the initial memory block pointer
    390  * @size:  an int specifying the size in byte to allocate.
    391  *
    392  * a realloc() equivalent, with logging of the allocation info.
    393  *
    394  * Returns a pointer to the allocated area or NULL in case of lack of memory.
    395  */
    396 
    397 void *
    398 xmlMemRealloc(void *ptr,size_t size) {
    399     return(xmlReallocLoc(ptr, size, "none", 0));
    400 }
    401 
    402 /**
    403  * xmlMemFree:
    404  * @ptr:  the memory block pointer
    405  *
    406  * a free() equivalent, with error checking.
    407  */
    408 void
    409 xmlMemFree(void *ptr)
    410 {
    411     MEMHDR *p;
    412     char *target;
    413 #ifdef DEBUG_MEMORY
    414     size_t size;
    415 #endif
    416 
    417     if (ptr == NULL)
    418 	return;
    419 
    420     if (ptr == (void *) -1) {
    421 	xmlGenericError(xmlGenericErrorContext,
    422 	    "trying to free pointer from freed area\n");
    423         goto error;
    424     }
    425 
    426     if (xmlMemTraceBlockAt == ptr) {
    427 	xmlGenericError(xmlGenericErrorContext,
    428 			"%p : Freed()\n", xmlMemTraceBlockAt);
    429 	xmlMallocBreakpoint();
    430     }
    431 
    432     TEST_POINT
    433 
    434     target = (char *) ptr;
    435 
    436     p = CLIENT_2_HDR(ptr);
    437     if (p->mh_tag != MEMTAG) {
    438         Mem_Tag_Err(p);
    439         goto error;
    440     }
    441     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
    442     p->mh_tag = ~MEMTAG;
    443     memset(target, -1, p->mh_size);
    444     xmlMutexLock(xmlMemMutex);
    445     debugMemSize -= p->mh_size;
    446     debugMemBlocks--;
    447 #ifdef DEBUG_MEMORY
    448     size = p->mh_size;
    449 #endif
    450 #ifdef MEM_LIST
    451     debugmem_list_delete(p);
    452 #endif
    453     xmlMutexUnlock(xmlMemMutex);
    454 
    455     free(p);
    456 
    457     TEST_POINT
    458 
    459 #ifdef DEBUG_MEMORY
    460     xmlGenericError(xmlGenericErrorContext,
    461 	    "Freed(%d) Ok\n", size);
    462 #endif
    463 
    464     return;
    465 
    466 error:
    467     xmlGenericError(xmlGenericErrorContext,
    468 	    "xmlMemFree(%lX) error\n", (unsigned long) ptr);
    469     xmlMallocBreakpoint();
    470     return;
    471 }
    472 
    473 /**
    474  * xmlMemStrdupLoc:
    475  * @str:  the initial string pointer
    476  * @file:  the file name or NULL
    477  * @line:  the line number
    478  *
    479  * a strdup() equivalent, with logging of the allocation info.
    480  *
    481  * Returns a pointer to the new string or NULL if allocation error occurred.
    482  */
    483 
    484 char *
    485 xmlMemStrdupLoc(const char *str, const char *file, int line)
    486 {
    487     char *s;
    488     size_t size = strlen(str) + 1;
    489     MEMHDR *p;
    490 
    491     if (!xmlMemInitialized) xmlInitMemory();
    492     TEST_POINT
    493 
    494     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
    495     if (!p) {
    496       goto error;
    497     }
    498     p->mh_tag = MEMTAG;
    499     p->mh_size = size;
    500     p->mh_type = STRDUP_TYPE;
    501     p->mh_file = file;
    502     p->mh_line = line;
    503     xmlMutexLock(xmlMemMutex);
    504     p->mh_number = ++block;
    505     debugMemSize += size;
    506     debugMemBlocks++;
    507     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
    508 #ifdef MEM_LIST
    509     debugmem_list_add(p);
    510 #endif
    511     xmlMutexUnlock(xmlMemMutex);
    512 
    513     s = (char *) HDR_2_CLIENT(p);
    514 
    515     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
    516 
    517     strcpy(s,str);
    518 
    519     TEST_POINT
    520 
    521     if (xmlMemTraceBlockAt == s) {
    522 	xmlGenericError(xmlGenericErrorContext,
    523 			"%p : Strdup() Ok\n", xmlMemTraceBlockAt);
    524 	xmlMallocBreakpoint();
    525     }
    526 
    527     return(s);
    528 
    529 error:
    530     return(NULL);
    531 }
    532 
    533 /**
    534  * xmlMemoryStrdup:
    535  * @str:  the initial string pointer
    536  *
    537  * a strdup() equivalent, with logging of the allocation info.
    538  *
    539  * Returns a pointer to the new string or NULL if allocation error occurred.
    540  */
    541 
    542 char *
    543 xmlMemoryStrdup(const char *str) {
    544     return(xmlMemStrdupLoc(str, "none", 0));
    545 }
    546 
    547 /**
    548  * xmlMemUsed:
    549  *
    550  * Provides the amount of memory currently allocated
    551  *
    552  * Returns an int representing the amount of memory allocated.
    553  */
    554 
    555 int
    556 xmlMemUsed(void) {
    557     int res;
    558 
    559     xmlMutexLock(xmlMemMutex);
    560     res = debugMemSize;
    561     xmlMutexUnlock(xmlMemMutex);
    562     return(res);
    563 }
    564 
    565 /**
    566  * xmlMemBlocks:
    567  *
    568  * Provides the number of memory areas currently allocated
    569  *
    570  * Returns an int representing the number of blocks
    571  */
    572 
    573 int
    574 xmlMemBlocks(void) {
    575     int res;
    576 
    577     xmlMutexLock(xmlMemMutex);
    578     res = debugMemBlocks;
    579     xmlMutexUnlock(xmlMemMutex);
    580     return(res);
    581 }
    582 
    583 #ifdef MEM_LIST
    584 /**
    585  * xmlMemContentShow:
    586  * @fp:  a FILE descriptor used as the output file
    587  * @p:  a memory block header
    588  *
    589  * tries to show some content from the memory block
    590  */
    591 
    592 static void
    593 xmlMemContentShow(FILE *fp, MEMHDR *p)
    594 {
    595     int i,j,k,len;
    596     const char *buf;
    597 
    598     if (p == NULL) {
    599 	fprintf(fp, " NULL");
    600 	return;
    601     }
    602     len = p->mh_size;
    603     buf = (const char *) HDR_2_CLIENT(p);
    604 
    605     for (i = 0;i < len;i++) {
    606         if (buf[i] == 0) break;
    607 	if (!isprint((unsigned char) buf[i])) break;
    608     }
    609     if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
    610         if (len >= 4) {
    611 	    MEMHDR *q;
    612 	    void *cur;
    613 
    614             for (j = 0;(j < len -3) && (j < 40);j += 4) {
    615 		cur = *((void **) &buf[j]);
    616 		q = CLIENT_2_HDR(cur);
    617 		p = memlist;
    618 		k = 0;
    619 		while (p != NULL) {
    620 		    if (p == q) break;
    621 		    p = p->mh_next;
    622 		    if (k++ > 100) break;
    623 		}
    624 		if ((p != NULL) && (p == q)) {
    625 		    fprintf(fp, " pointer to #%lu at index %d",
    626 		            p->mh_number, j);
    627 		    return;
    628 		}
    629 	    }
    630 	}
    631     } else if ((i == 0) && (buf[i] == 0)) {
    632         fprintf(fp," null");
    633     } else {
    634         if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
    635 	else {
    636             fprintf(fp," [");
    637 	    for (j = 0;j < i;j++)
    638                 fprintf(fp,"%c", buf[j]);
    639             fprintf(fp,"]");
    640 	}
    641     }
    642 }
    643 #endif
    644 
    645 /**
    646  * xmlMemDisplayLast:
    647  * @fp:  a FILE descriptor used as the output file, if NULL, the result is
    648  *       written to the file .memorylist
    649  * @nbBytes: the amount of memory to dump
    650  *
    651  * the last nbBytes of memory allocated and not freed, useful for dumping
    652  * the memory left allocated between two places at runtime.
    653  */
    654 
    655 void
    656 xmlMemDisplayLast(FILE *fp, long nbBytes)
    657 {
    658 #ifdef MEM_LIST
    659     MEMHDR *p;
    660     unsigned idx;
    661     int     nb = 0;
    662 #endif
    663     FILE *old_fp = fp;
    664 
    665     if (nbBytes <= 0)
    666         return;
    667 
    668     if (fp == NULL) {
    669 	fp = fopen(".memorylist", "w");
    670 	if (fp == NULL)
    671 	    return;
    672     }
    673 
    674 #ifdef MEM_LIST
    675     fprintf(fp,"   Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
    676             nbBytes, debugMemSize, debugMaxMemSize);
    677     fprintf(fp,"BLOCK  NUMBER   SIZE  TYPE\n");
    678     idx = 0;
    679     xmlMutexLock(xmlMemMutex);
    680     p = memlist;
    681     while ((p) && (nbBytes > 0)) {
    682 	  fprintf(fp,"%-5u  %6lu %6lu ",idx++,p->mh_number,
    683 		  (unsigned long)p->mh_size);
    684         switch (p->mh_type) {
    685            case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
    686            case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
    687            case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
    688            case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
    689            case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
    690            default:
    691 	        fprintf(fp,"Unknown memory block, may be corrupted");
    692 		xmlMutexUnlock(xmlMemMutex);
    693 		if (old_fp == NULL)
    694 		    fclose(fp);
    695 		return;
    696         }
    697 	if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
    698         if (p->mh_tag != MEMTAG)
    699 	      fprintf(fp,"  INVALID");
    700         nb++;
    701 	if (nb < 100)
    702 	    xmlMemContentShow(fp, p);
    703 	else
    704 	    fprintf(fp," skip");
    705 
    706         fprintf(fp,"\n");
    707 	nbBytes -= (unsigned long)p->mh_size;
    708         p = p->mh_next;
    709     }
    710     xmlMutexUnlock(xmlMemMutex);
    711 #else
    712     fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
    713 #endif
    714     if (old_fp == NULL)
    715 	fclose(fp);
    716 }
    717 
    718 /**
    719  * xmlMemDisplay:
    720  * @fp:  a FILE descriptor used as the output file, if NULL, the result is
    721  *       written to the file .memorylist
    722  *
    723  * show in-extenso the memory blocks allocated
    724  */
    725 
    726 void
    727 xmlMemDisplay(FILE *fp)
    728 {
    729 #ifdef MEM_LIST
    730     MEMHDR *p;
    731     unsigned idx;
    732     int     nb = 0;
    733 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
    734     time_t currentTime;
    735     char buf[500];
    736     struct tm * tstruct;
    737 #endif
    738 #endif
    739     FILE *old_fp = fp;
    740 
    741     if (fp == NULL) {
    742 	fp = fopen(".memorylist", "w");
    743 	if (fp == NULL)
    744 	    return;
    745     }
    746 
    747 #ifdef MEM_LIST
    748 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
    749     currentTime = time(NULL);
    750     tstruct = localtime(&currentTime);
    751     strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
    752     fprintf(fp,"      %s\n\n", buf);
    753 #endif
    754 
    755 
    756     fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
    757             debugMemSize, debugMaxMemSize);
    758     fprintf(fp,"BLOCK  NUMBER   SIZE  TYPE\n");
    759     idx = 0;
    760     xmlMutexLock(xmlMemMutex);
    761     p = memlist;
    762     while (p) {
    763 	  fprintf(fp,"%-5u  %6lu %6lu ",idx++,p->mh_number,
    764 		  (unsigned long)p->mh_size);
    765         switch (p->mh_type) {
    766            case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
    767            case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
    768            case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
    769            case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
    770            case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
    771            default:
    772 	        fprintf(fp,"Unknown memory block, may be corrupted");
    773 		xmlMutexUnlock(xmlMemMutex);
    774 		if (old_fp == NULL)
    775 		    fclose(fp);
    776 		return;
    777         }
    778 	if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
    779         if (p->mh_tag != MEMTAG)
    780 	      fprintf(fp,"  INVALID");
    781         nb++;
    782 	if (nb < 100)
    783 	    xmlMemContentShow(fp, p);
    784 	else
    785 	    fprintf(fp," skip");
    786 
    787         fprintf(fp,"\n");
    788         p = p->mh_next;
    789     }
    790     xmlMutexUnlock(xmlMemMutex);
    791 #else
    792     fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
    793 #endif
    794     if (old_fp == NULL)
    795 	fclose(fp);
    796 }
    797 
    798 #ifdef MEM_LIST
    799 
    800 static void debugmem_list_add(MEMHDR *p)
    801 {
    802      p->mh_next = memlist;
    803      p->mh_prev = NULL;
    804      if (memlist) memlist->mh_prev = p;
    805      memlist = p;
    806 #ifdef MEM_LIST_DEBUG
    807      if (stderr)
    808      Mem_Display(stderr);
    809 #endif
    810 }
    811 
    812 static void debugmem_list_delete(MEMHDR *p)
    813 {
    814      if (p->mh_next)
    815      p->mh_next->mh_prev = p->mh_prev;
    816      if (p->mh_prev)
    817      p->mh_prev->mh_next = p->mh_next;
    818      else memlist = p->mh_next;
    819 #ifdef MEM_LIST_DEBUG
    820      if (stderr)
    821      Mem_Display(stderr);
    822 #endif
    823 }
    824 
    825 #endif
    826 
    827 /*
    828  * debugmem_tag_error:
    829  *
    830  * internal error function.
    831  */
    832 
    833 static void debugmem_tag_error(void *p)
    834 {
    835      xmlGenericError(xmlGenericErrorContext,
    836 	     "Memory tag error occurs :%p \n\t bye\n", p);
    837 #ifdef MEM_LIST
    838      if (stderr)
    839      xmlMemDisplay(stderr);
    840 #endif
    841 }
    842 
    843 #ifdef MEM_LIST
    844 static FILE *xmlMemoryDumpFile = NULL;
    845 #endif
    846 
    847 /**
    848  * xmlMemShow:
    849  * @fp:  a FILE descriptor used as the output file
    850  * @nr:  number of entries to dump
    851  *
    852  * show a show display of the memory allocated, and dump
    853  * the @nr last allocated areas which were not freed
    854  */
    855 
    856 void
    857 xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
    858 {
    859 #ifdef MEM_LIST
    860     MEMHDR *p;
    861 #endif
    862 
    863     if (fp != NULL)
    864 	fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
    865 		debugMemSize, debugMaxMemSize);
    866 #ifdef MEM_LIST
    867     xmlMutexLock(xmlMemMutex);
    868     if (nr > 0) {
    869 	fprintf(fp,"NUMBER   SIZE  TYPE   WHERE\n");
    870 	p = memlist;
    871 	while ((p) && nr > 0) {
    872 	      fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
    873 	    switch (p->mh_type) {
    874 	       case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
    875 	       case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
    876 	       case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
    877 	      case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
    878 	      case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
    879 		default:fprintf(fp,"   ???    in ");break;
    880 	    }
    881 	    if (p->mh_file != NULL)
    882 	        fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
    883 	    if (p->mh_tag != MEMTAG)
    884 		fprintf(fp,"  INVALID");
    885 	    xmlMemContentShow(fp, p);
    886 	    fprintf(fp,"\n");
    887 	    nr--;
    888 	    p = p->mh_next;
    889 	}
    890     }
    891     xmlMutexUnlock(xmlMemMutex);
    892 #endif /* MEM_LIST */
    893 }
    894 
    895 /**
    896  * xmlMemoryDump:
    897  *
    898  * Dump in-extenso the memory blocks allocated to the file .memorylist
    899  */
    900 
    901 void
    902 xmlMemoryDump(void)
    903 {
    904 #ifdef MEM_LIST
    905     FILE *dump;
    906 
    907     if (debugMaxMemSize == 0)
    908 	return;
    909     dump = fopen(".memdump", "w");
    910     if (dump == NULL)
    911 	xmlMemoryDumpFile = stderr;
    912     else xmlMemoryDumpFile = dump;
    913 
    914     xmlMemDisplay(xmlMemoryDumpFile);
    915 
    916     if (dump != NULL) fclose(dump);
    917 #endif /* MEM_LIST */
    918 }
    919 
    920 
    921 /****************************************************************
    922  *								*
    923  *		Initialization Routines				*
    924  *								*
    925  ****************************************************************/
    926 
    927 /**
    928  * xmlInitMemory:
    929  *
    930  * Initialize the memory layer.
    931  *
    932  * Returns 0 on success
    933  */
    934 int
    935 xmlInitMemory(void)
    936 {
    937 #ifdef HAVE_STDLIB_H
    938      char *breakpoint;
    939 #endif
    940 #ifdef DEBUG_MEMORY
    941      xmlGenericError(xmlGenericErrorContext,
    942 	     "xmlInitMemory()\n");
    943 #endif
    944     /*
    945      This is really not good code (see Bug 130419).  Suggestions for
    946      improvement will be welcome!
    947     */
    948      if (xmlMemInitialized) return(-1);
    949      xmlMemInitialized = 1;
    950      xmlMemMutex = xmlNewMutex();
    951 
    952 #ifdef HAVE_STDLIB_H
    953      breakpoint = getenv("XML_MEM_BREAKPOINT");
    954      if (breakpoint != NULL) {
    955          sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
    956      }
    957 #endif
    958 #ifdef HAVE_STDLIB_H
    959      breakpoint = getenv("XML_MEM_TRACE");
    960      if (breakpoint != NULL) {
    961          sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
    962      }
    963 #endif
    964 
    965 #ifdef DEBUG_MEMORY
    966      xmlGenericError(xmlGenericErrorContext,
    967 	     "xmlInitMemory() Ok\n");
    968 #endif
    969      return(0);
    970 }
    971 
    972 /**
    973  * xmlCleanupMemory:
    974  *
    975  * Free up all the memory allocated by the library for its own
    976  * use. This should not be called by user level code.
    977  */
    978 void
    979 xmlCleanupMemory(void) {
    980 #ifdef DEBUG_MEMORY
    981      xmlGenericError(xmlGenericErrorContext,
    982 	     "xmlCleanupMemory()\n");
    983 #endif
    984     if (xmlMemInitialized == 0)
    985         return;
    986 
    987     xmlFreeMutex(xmlMemMutex);
    988     xmlMemMutex = NULL;
    989     xmlMemInitialized = 0;
    990 #ifdef DEBUG_MEMORY
    991      xmlGenericError(xmlGenericErrorContext,
    992 	     "xmlCleanupMemory() Ok\n");
    993 #endif
    994 }
    995 
    996 /**
    997  * xmlMemSetup:
    998  * @freeFunc: the free() function to use
    999  * @mallocFunc: the malloc() function to use
   1000  * @reallocFunc: the realloc() function to use
   1001  * @strdupFunc: the strdup() function to use
   1002  *
   1003  * Override the default memory access functions with a new set
   1004  * This has to be called before any other libxml routines !
   1005  *
   1006  * Should this be blocked if there was already some allocations
   1007  * done ?
   1008  *
   1009  * Returns 0 on success
   1010  */
   1011 int
   1012 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
   1013             xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
   1014 #ifdef DEBUG_MEMORY
   1015      xmlGenericError(xmlGenericErrorContext,
   1016 	     "xmlMemSetup()\n");
   1017 #endif
   1018     if (freeFunc == NULL)
   1019 	return(-1);
   1020     if (mallocFunc == NULL)
   1021 	return(-1);
   1022     if (reallocFunc == NULL)
   1023 	return(-1);
   1024     if (strdupFunc == NULL)
   1025 	return(-1);
   1026     xmlFree = freeFunc;
   1027     xmlMalloc = mallocFunc;
   1028     xmlMallocAtomic = mallocFunc;
   1029     xmlRealloc = reallocFunc;
   1030     xmlMemStrdup = strdupFunc;
   1031 #ifdef DEBUG_MEMORY
   1032      xmlGenericError(xmlGenericErrorContext,
   1033 	     "xmlMemSetup() Ok\n");
   1034 #endif
   1035     return(0);
   1036 }
   1037 
   1038 /**
   1039  * xmlMemGet:
   1040  * @freeFunc: place to save the free() function in use
   1041  * @mallocFunc: place to save the malloc() function in use
   1042  * @reallocFunc: place to save the realloc() function in use
   1043  * @strdupFunc: place to save the strdup() function in use
   1044  *
   1045  * Provides the memory access functions set currently in use
   1046  *
   1047  * Returns 0 on success
   1048  */
   1049 int
   1050 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
   1051 	  xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
   1052     if (freeFunc != NULL) *freeFunc = xmlFree;
   1053     if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
   1054     if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
   1055     if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
   1056     return(0);
   1057 }
   1058 
   1059 /**
   1060  * xmlGcMemSetup:
   1061  * @freeFunc: the free() function to use
   1062  * @mallocFunc: the malloc() function to use
   1063  * @mallocAtomicFunc: the malloc() function to use for atomic allocations
   1064  * @reallocFunc: the realloc() function to use
   1065  * @strdupFunc: the strdup() function to use
   1066  *
   1067  * Override the default memory access functions with a new set
   1068  * This has to be called before any other libxml routines !
   1069  * The mallocAtomicFunc is specialized for atomic block
   1070  * allocations (i.e. of areas  useful for garbage collected memory allocators
   1071  *
   1072  * Should this be blocked if there was already some allocations
   1073  * done ?
   1074  *
   1075  * Returns 0 on success
   1076  */
   1077 int
   1078 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
   1079               xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
   1080 	      xmlStrdupFunc strdupFunc) {
   1081 #ifdef DEBUG_MEMORY
   1082      xmlGenericError(xmlGenericErrorContext,
   1083 	     "xmlGcMemSetup()\n");
   1084 #endif
   1085     if (freeFunc == NULL)
   1086 	return(-1);
   1087     if (mallocFunc == NULL)
   1088 	return(-1);
   1089     if (mallocAtomicFunc == NULL)
   1090 	return(-1);
   1091     if (reallocFunc == NULL)
   1092 	return(-1);
   1093     if (strdupFunc == NULL)
   1094 	return(-1);
   1095     xmlFree = freeFunc;
   1096     xmlMalloc = mallocFunc;
   1097     xmlMallocAtomic = mallocAtomicFunc;
   1098     xmlRealloc = reallocFunc;
   1099     xmlMemStrdup = strdupFunc;
   1100 #ifdef DEBUG_MEMORY
   1101      xmlGenericError(xmlGenericErrorContext,
   1102 	     "xmlGcMemSetup() Ok\n");
   1103 #endif
   1104     return(0);
   1105 }
   1106 
   1107 /**
   1108  * xmlGcMemGet:
   1109  * @freeFunc: place to save the free() function in use
   1110  * @mallocFunc: place to save the malloc() function in use
   1111  * @mallocAtomicFunc: place to save the atomic malloc() function in use
   1112  * @reallocFunc: place to save the realloc() function in use
   1113  * @strdupFunc: place to save the strdup() function in use
   1114  *
   1115  * Provides the memory access functions set currently in use
   1116  * The mallocAtomicFunc is specialized for atomic block
   1117  * allocations (i.e. of areas  useful for garbage collected memory allocators
   1118  *
   1119  * Returns 0 on success
   1120  */
   1121 int
   1122 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
   1123             xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
   1124 	    xmlStrdupFunc *strdupFunc) {
   1125     if (freeFunc != NULL) *freeFunc = xmlFree;
   1126     if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
   1127     if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
   1128     if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
   1129     if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
   1130     return(0);
   1131 }
   1132 
   1133 #define bottom_xmlmemory
   1134 #include "elfgcchack.h"
   1135