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