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;
    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     p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
    348     if (!p) {
    349 	 goto error;
    350     }
    351     if (xmlMemTraceBlockAt == ptr) {
    352 	xmlGenericError(xmlGenericErrorContext,
    353 			"%p : Realloced(%lu -> %lu) Ok\n",
    354 			xmlMemTraceBlockAt, (long unsigned)p->mh_size,
    355 			(long unsigned)size);
    356 	xmlMallocBreakpoint();
    357     }
    358     p->mh_tag = MEMTAG;
    359     p->mh_number = number;
    360     p->mh_type = REALLOC_TYPE;
    361     p->mh_size = size;
    362     p->mh_file = file;
    363     p->mh_line = line;
    364     xmlMutexLock(xmlMemMutex);
    365     debugMemSize += size;
    366     debugMemBlocks++;
    367     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
    368 #ifdef MEM_LIST
    369     debugmem_list_add(p);
    370 #endif
    371     xmlMutexUnlock(xmlMemMutex);
    372 
    373     TEST_POINT
    374 
    375 #ifdef DEBUG_MEMORY
    376     xmlGenericError(xmlGenericErrorContext,
    377 	    "Realloced(%d to %d) Ok\n", oldsize, size);
    378 #endif
    379     return(HDR_2_CLIENT(p));
    380 
    381 error:
    382     return(NULL);
    383 }
    384 
    385 /**
    386  * xmlMemRealloc:
    387  * @ptr:  the initial memory block pointer
    388  * @size:  an int specifying the size in byte to allocate.
    389  *
    390  * a realloc() equivalent, with logging of the allocation info.
    391  *
    392  * Returns a pointer to the allocated area or NULL in case of lack of memory.
    393  */
    394 
    395 void *
    396 xmlMemRealloc(void *ptr,size_t size) {
    397     return(xmlReallocLoc(ptr, size, "none", 0));
    398 }
    399 
    400 /**
    401  * xmlMemFree:
    402  * @ptr:  the memory block pointer
    403  *
    404  * a free() equivalent, with error checking.
    405  */
    406 void
    407 xmlMemFree(void *ptr)
    408 {
    409     MEMHDR *p;
    410     char *target;
    411 #ifdef DEBUG_MEMORY
    412     size_t size;
    413 #endif
    414 
    415     if (ptr == NULL)
    416 	return;
    417 
    418     if (ptr == (void *) -1) {
    419 	xmlGenericError(xmlGenericErrorContext,
    420 	    "trying to free pointer from freed area\n");
    421         goto error;
    422     }
    423 
    424     if (xmlMemTraceBlockAt == ptr) {
    425 	xmlGenericError(xmlGenericErrorContext,
    426 			"%p : Freed()\n", xmlMemTraceBlockAt);
    427 	xmlMallocBreakpoint();
    428     }
    429 
    430     TEST_POINT
    431 
    432     target = (char *) ptr;
    433 
    434     p = CLIENT_2_HDR(ptr);
    435     if (p->mh_tag != MEMTAG) {
    436         Mem_Tag_Err(p);
    437         goto error;
    438     }
    439     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
    440     p->mh_tag = ~MEMTAG;
    441     memset(target, -1, p->mh_size);
    442     xmlMutexLock(xmlMemMutex);
    443     debugMemSize -= p->mh_size;
    444     debugMemBlocks--;
    445 #ifdef DEBUG_MEMORY
    446     size = p->mh_size;
    447 #endif
    448 #ifdef MEM_LIST
    449     debugmem_list_delete(p);
    450 #endif
    451     xmlMutexUnlock(xmlMemMutex);
    452 
    453     free(p);
    454 
    455     TEST_POINT
    456 
    457 #ifdef DEBUG_MEMORY
    458     xmlGenericError(xmlGenericErrorContext,
    459 	    "Freed(%d) Ok\n", size);
    460 #endif
    461 
    462     return;
    463 
    464 error:
    465     xmlGenericError(xmlGenericErrorContext,
    466 	    "xmlMemFree(%lX) error\n", (unsigned long) ptr);
    467     xmlMallocBreakpoint();
    468     return;
    469 }
    470 
    471 /**
    472  * xmlMemStrdupLoc:
    473  * @str:  the initial string pointer
    474  * @file:  the file name or NULL
    475  * @line:  the line number
    476  *
    477  * a strdup() equivalent, with logging of the allocation info.
    478  *
    479  * Returns a pointer to the new string or NULL if allocation error occurred.
    480  */
    481 
    482 char *
    483 xmlMemStrdupLoc(const char *str, const char *file, int line)
    484 {
    485     char *s;
    486     size_t size = strlen(str) + 1;
    487     MEMHDR *p;
    488 
    489     if (!xmlMemInitialized) xmlInitMemory();
    490     TEST_POINT
    491 
    492     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
    493     if (!p) {
    494       goto error;
    495     }
    496     p->mh_tag = MEMTAG;
    497     p->mh_size = size;
    498     p->mh_type = STRDUP_TYPE;
    499     p->mh_file = file;
    500     p->mh_line = line;
    501     xmlMutexLock(xmlMemMutex);
    502     p->mh_number = ++block;
    503     debugMemSize += size;
    504     debugMemBlocks++;
    505     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
    506 #ifdef MEM_LIST
    507     debugmem_list_add(p);
    508 #endif
    509     xmlMutexUnlock(xmlMemMutex);
    510 
    511     s = (char *) HDR_2_CLIENT(p);
    512 
    513     if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint();
    514 
    515     if (s != NULL)
    516       strcpy(s,str);
    517     else
    518       goto error;
    519 
    520     TEST_POINT
    521 
    522     if (xmlMemTraceBlockAt == s) {
    523 	xmlGenericError(xmlGenericErrorContext,
    524 			"%p : Strdup() Ok\n", xmlMemTraceBlockAt);
    525 	xmlMallocBreakpoint();
    526     }
    527 
    528     return(s);
    529 
    530 error:
    531     return(NULL);
    532 }
    533 
    534 /**
    535  * xmlMemoryStrdup:
    536  * @str:  the initial string pointer
    537  *
    538  * a strdup() equivalent, with logging of the allocation info.
    539  *
    540  * Returns a pointer to the new string or NULL if allocation error occurred.
    541  */
    542 
    543 char *
    544 xmlMemoryStrdup(const char *str) {
    545     return(xmlMemStrdupLoc(str, "none", 0));
    546 }
    547 
    548 /**
    549  * xmlMemUsed:
    550  *
    551  * Provides the amount of memory currently allocated
    552  *
    553  * Returns an int representing the amount of memory allocated.
    554  */
    555 
    556 int
    557 xmlMemUsed(void) {
    558      return(debugMemSize);
    559 }
    560 
    561 /**
    562  * xmlMemBlocks:
    563  *
    564  * Provides the number of memory areas currently allocated
    565  *
    566  * Returns an int representing the number of blocks
    567  */
    568 
    569 int
    570 xmlMemBlocks(void) {
    571      return(debugMemBlocks);
    572 }
    573 
    574 #ifdef MEM_LIST
    575 /**
    576  * xmlMemContentShow:
    577  * @fp:  a FILE descriptor used as the output file
    578  * @p:  a memory block header
    579  *
    580  * tries to show some content from the memory block
    581  */
    582 
    583 static void
    584 xmlMemContentShow(FILE *fp, MEMHDR *p)
    585 {
    586     int i,j,k,len = p->mh_size;
    587     const char *buf = (const char *) HDR_2_CLIENT(p);
    588 
    589     if (p == NULL) {
    590 	fprintf(fp, " NULL");
    591 	return;
    592     }
    593 
    594     for (i = 0;i < len;i++) {
    595         if (buf[i] == 0) break;
    596 	if (!isprint((unsigned char) buf[i])) break;
    597     }
    598     if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
    599         if (len >= 4) {
    600 	    MEMHDR *q;
    601 	    void *cur;
    602 
    603             for (j = 0;(j < len -3) && (j < 40);j += 4) {
    604 		cur = *((void **) &buf[j]);
    605 		q = CLIENT_2_HDR(cur);
    606 		p = memlist;
    607 		k = 0;
    608 		while (p != NULL) {
    609 		    if (p == q) break;
    610 		    p = p->mh_next;
    611 		    if (k++ > 100) break;
    612 		}
    613 		if ((p != NULL) && (p == q)) {
    614 		    fprintf(fp, " pointer to #%lu at index %d",
    615 		            p->mh_number, j);
    616 		    return;
    617 		}
    618 	    }
    619 	}
    620     } else if ((i == 0) && (buf[i] == 0)) {
    621         fprintf(fp," null");
    622     } else {
    623         if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf);
    624 	else {
    625             fprintf(fp," [");
    626 	    for (j = 0;j < i;j++)
    627                 fprintf(fp,"%c", buf[j]);
    628             fprintf(fp,"]");
    629 	}
    630     }
    631 }
    632 #endif
    633 
    634 /**
    635  * xmlMemDisplayLast:
    636  * @fp:  a FILE descriptor used as the output file, if NULL, the result is
    637  *       written to the file .memorylist
    638  * @nbBytes: the amount of memory to dump
    639  *
    640  * the last nbBytes of memory allocated and not freed, useful for dumping
    641  * the memory left allocated between two places at runtime.
    642  */
    643 
    644 void
    645 xmlMemDisplayLast(FILE *fp, long nbBytes)
    646 {
    647 #ifdef MEM_LIST
    648     MEMHDR *p;
    649     unsigned idx;
    650     int     nb = 0;
    651 #endif
    652     FILE *old_fp = fp;
    653 
    654     if (nbBytes <= 0)
    655         return;
    656 
    657     if (fp == NULL) {
    658 	fp = fopen(".memorylist", "w");
    659 	if (fp == NULL)
    660 	    return;
    661     }
    662 
    663 #ifdef MEM_LIST
    664     fprintf(fp,"   Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n",
    665             nbBytes, debugMemSize, debugMaxMemSize);
    666     fprintf(fp,"BLOCK  NUMBER   SIZE  TYPE\n");
    667     idx = 0;
    668     xmlMutexLock(xmlMemMutex);
    669     p = memlist;
    670     while ((p) && (nbBytes > 0)) {
    671 	  fprintf(fp,"%-5u  %6lu %6lu ",idx++,p->mh_number,
    672 		  (unsigned long)p->mh_size);
    673         switch (p->mh_type) {
    674            case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
    675            case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
    676            case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
    677            case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
    678            case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
    679            default:
    680 	        fprintf(fp,"Unknown memory block, may be corrupted");
    681 		xmlMutexUnlock(xmlMemMutex);
    682 		if (old_fp == NULL)
    683 		    fclose(fp);
    684 		return;
    685         }
    686 	if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
    687         if (p->mh_tag != MEMTAG)
    688 	      fprintf(fp,"  INVALID");
    689         nb++;
    690 	if (nb < 100)
    691 	    xmlMemContentShow(fp, p);
    692 	else
    693 	    fprintf(fp," skip");
    694 
    695         fprintf(fp,"\n");
    696 	nbBytes -= (unsigned long)p->mh_size;
    697         p = p->mh_next;
    698     }
    699     xmlMutexUnlock(xmlMemMutex);
    700 #else
    701     fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
    702 #endif
    703     if (old_fp == NULL)
    704 	fclose(fp);
    705 }
    706 
    707 /**
    708  * xmlMemDisplay:
    709  * @fp:  a FILE descriptor used as the output file, if NULL, the result is
    710  *       written to the file .memorylist
    711  *
    712  * show in-extenso the memory blocks allocated
    713  */
    714 
    715 void
    716 xmlMemDisplay(FILE *fp)
    717 {
    718 #ifdef MEM_LIST
    719     MEMHDR *p;
    720     unsigned idx;
    721     int     nb = 0;
    722 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
    723     time_t currentTime;
    724     char buf[500];
    725     struct tm * tstruct;
    726 #endif
    727 #endif
    728     FILE *old_fp = fp;
    729 
    730     if (fp == NULL) {
    731 	fp = fopen(".memorylist", "w");
    732 	if (fp == NULL)
    733 	    return;
    734     }
    735 
    736 #ifdef MEM_LIST
    737 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
    738     currentTime = time(NULL);
    739     tstruct = localtime(&currentTime);
    740     strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct);
    741     fprintf(fp,"      %s\n\n", buf);
    742 #endif
    743 
    744 
    745     fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
    746             debugMemSize, debugMaxMemSize);
    747     fprintf(fp,"BLOCK  NUMBER   SIZE  TYPE\n");
    748     idx = 0;
    749     xmlMutexLock(xmlMemMutex);
    750     p = memlist;
    751     while (p) {
    752 	  fprintf(fp,"%-5u  %6lu %6lu ",idx++,p->mh_number,
    753 		  (unsigned long)p->mh_size);
    754         switch (p->mh_type) {
    755            case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
    756            case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
    757            case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
    758            case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
    759            case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
    760            default:
    761 	        fprintf(fp,"Unknown memory block, may be corrupted");
    762 		xmlMutexUnlock(xmlMemMutex);
    763 		if (old_fp == NULL)
    764 		    fclose(fp);
    765 		return;
    766         }
    767 	if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
    768         if (p->mh_tag != MEMTAG)
    769 	      fprintf(fp,"  INVALID");
    770         nb++;
    771 	if (nb < 100)
    772 	    xmlMemContentShow(fp, p);
    773 	else
    774 	    fprintf(fp," skip");
    775 
    776         fprintf(fp,"\n");
    777         p = p->mh_next;
    778     }
    779     xmlMutexUnlock(xmlMemMutex);
    780 #else
    781     fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
    782 #endif
    783     if (old_fp == NULL)
    784 	fclose(fp);
    785 }
    786 
    787 #ifdef MEM_LIST
    788 
    789 static void debugmem_list_add(MEMHDR *p)
    790 {
    791      p->mh_next = memlist;
    792      p->mh_prev = NULL;
    793      if (memlist) memlist->mh_prev = p;
    794      memlist = p;
    795 #ifdef MEM_LIST_DEBUG
    796      if (stderr)
    797      Mem_Display(stderr);
    798 #endif
    799 }
    800 
    801 static void debugmem_list_delete(MEMHDR *p)
    802 {
    803      if (p->mh_next)
    804      p->mh_next->mh_prev = p->mh_prev;
    805      if (p->mh_prev)
    806      p->mh_prev->mh_next = p->mh_next;
    807      else memlist = p->mh_next;
    808 #ifdef MEM_LIST_DEBUG
    809      if (stderr)
    810      Mem_Display(stderr);
    811 #endif
    812 }
    813 
    814 #endif
    815 
    816 /*
    817  * debugmem_tag_error:
    818  *
    819  * internal error function.
    820  */
    821 
    822 static void debugmem_tag_error(void *p)
    823 {
    824      xmlGenericError(xmlGenericErrorContext,
    825 	     "Memory tag error occurs :%p \n\t bye\n", p);
    826 #ifdef MEM_LIST
    827      if (stderr)
    828      xmlMemDisplay(stderr);
    829 #endif
    830 }
    831 
    832 #ifdef MEM_LIST
    833 static FILE *xmlMemoryDumpFile = NULL;
    834 #endif
    835 
    836 /**
    837  * xmlMemShow:
    838  * @fp:  a FILE descriptor used as the output file
    839  * @nr:  number of entries to dump
    840  *
    841  * show a show display of the memory allocated, and dump
    842  * the @nr last allocated areas which were not freed
    843  */
    844 
    845 void
    846 xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED)
    847 {
    848 #ifdef MEM_LIST
    849     MEMHDR *p;
    850 #endif
    851 
    852     if (fp != NULL)
    853 	fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
    854 		debugMemSize, debugMaxMemSize);
    855 #ifdef MEM_LIST
    856     xmlMutexLock(xmlMemMutex);
    857     if (nr > 0) {
    858 	fprintf(fp,"NUMBER   SIZE  TYPE   WHERE\n");
    859 	p = memlist;
    860 	while ((p) && nr > 0) {
    861 	      fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size);
    862 	    switch (p->mh_type) {
    863 	       case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
    864 	       case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
    865 	       case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc()  in ");break;
    866 	      case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
    867 	      case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break;
    868 		default:fprintf(fp,"   ???    in ");break;
    869 	    }
    870 	    if (p->mh_file != NULL)
    871 	        fprintf(fp,"%s(%u)", p->mh_file, p->mh_line);
    872 	    if (p->mh_tag != MEMTAG)
    873 		fprintf(fp,"  INVALID");
    874 	    xmlMemContentShow(fp, p);
    875 	    fprintf(fp,"\n");
    876 	    nr--;
    877 	    p = p->mh_next;
    878 	}
    879     }
    880     xmlMutexUnlock(xmlMemMutex);
    881 #endif /* MEM_LIST */
    882 }
    883 
    884 /**
    885  * xmlMemoryDump:
    886  *
    887  * Dump in-extenso the memory blocks allocated to the file .memorylist
    888  */
    889 
    890 void
    891 xmlMemoryDump(void)
    892 {
    893 #ifdef MEM_LIST
    894     FILE *dump;
    895 
    896     if (debugMaxMemSize == 0)
    897 	return;
    898     dump = fopen(".memdump", "w");
    899     if (dump == NULL)
    900 	xmlMemoryDumpFile = stderr;
    901     else xmlMemoryDumpFile = dump;
    902 
    903     xmlMemDisplay(xmlMemoryDumpFile);
    904 
    905     if (dump != NULL) fclose(dump);
    906 #endif /* MEM_LIST */
    907 }
    908 
    909 
    910 /****************************************************************
    911  *								*
    912  *		Initialization Routines				*
    913  *								*
    914  ****************************************************************/
    915 
    916 /**
    917  * xmlInitMemory:
    918  *
    919  * Initialize the memory layer.
    920  *
    921  * Returns 0 on success
    922  */
    923 int
    924 xmlInitMemory(void)
    925 {
    926 #ifdef HAVE_STDLIB_H
    927      char *breakpoint;
    928 #endif
    929 #ifdef DEBUG_MEMORY
    930      xmlGenericError(xmlGenericErrorContext,
    931 	     "xmlInitMemory()\n");
    932 #endif
    933     /*
    934      This is really not good code (see Bug 130419).  Suggestions for
    935      improvement will be welcome!
    936     */
    937      if (xmlMemInitialized) return(-1);
    938      xmlMemInitialized = 1;
    939      xmlMemMutex = xmlNewMutex();
    940 
    941 #ifdef HAVE_STDLIB_H
    942      breakpoint = getenv("XML_MEM_BREAKPOINT");
    943      if (breakpoint != NULL) {
    944          sscanf(breakpoint, "%ud", &xmlMemStopAtBlock);
    945      }
    946 #endif
    947 #ifdef HAVE_STDLIB_H
    948      breakpoint = getenv("XML_MEM_TRACE");
    949      if (breakpoint != NULL) {
    950          sscanf(breakpoint, "%p", &xmlMemTraceBlockAt);
    951      }
    952 #endif
    953 
    954 #ifdef DEBUG_MEMORY
    955      xmlGenericError(xmlGenericErrorContext,
    956 	     "xmlInitMemory() Ok\n");
    957 #endif
    958      return(0);
    959 }
    960 
    961 /**
    962  * xmlCleanupMemory:
    963  *
    964  * Free up all the memory allocated by the library for its own
    965  * use. This should not be called by user level code.
    966  */
    967 void
    968 xmlCleanupMemory(void) {
    969 #ifdef DEBUG_MEMORY
    970      xmlGenericError(xmlGenericErrorContext,
    971 	     "xmlCleanupMemory()\n");
    972 #endif
    973     if (xmlMemInitialized == 0)
    974         return;
    975 
    976     xmlFreeMutex(xmlMemMutex);
    977     xmlMemMutex = NULL;
    978     xmlMemInitialized = 0;
    979 #ifdef DEBUG_MEMORY
    980      xmlGenericError(xmlGenericErrorContext,
    981 	     "xmlCleanupMemory() Ok\n");
    982 #endif
    983 }
    984 
    985 /**
    986  * xmlMemSetup:
    987  * @freeFunc: the free() function to use
    988  * @mallocFunc: the malloc() function to use
    989  * @reallocFunc: the realloc() function to use
    990  * @strdupFunc: the strdup() function to use
    991  *
    992  * Override the default memory access functions with a new set
    993  * This has to be called before any other libxml routines !
    994  *
    995  * Should this be blocked if there was already some allocations
    996  * done ?
    997  *
    998  * Returns 0 on success
    999  */
   1000 int
   1001 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
   1002             xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
   1003 #ifdef DEBUG_MEMORY
   1004      xmlGenericError(xmlGenericErrorContext,
   1005 	     "xmlMemSetup()\n");
   1006 #endif
   1007     if (freeFunc == NULL)
   1008 	return(-1);
   1009     if (mallocFunc == NULL)
   1010 	return(-1);
   1011     if (reallocFunc == NULL)
   1012 	return(-1);
   1013     if (strdupFunc == NULL)
   1014 	return(-1);
   1015     xmlFree = freeFunc;
   1016     xmlMalloc = mallocFunc;
   1017     xmlMallocAtomic = mallocFunc;
   1018     xmlRealloc = reallocFunc;
   1019     xmlMemStrdup = strdupFunc;
   1020 #ifdef DEBUG_MEMORY
   1021      xmlGenericError(xmlGenericErrorContext,
   1022 	     "xmlMemSetup() Ok\n");
   1023 #endif
   1024     return(0);
   1025 }
   1026 
   1027 /**
   1028  * xmlMemGet:
   1029  * @freeFunc: place to save the free() function in use
   1030  * @mallocFunc: place to save the malloc() function in use
   1031  * @reallocFunc: place to save the realloc() function in use
   1032  * @strdupFunc: place to save the strdup() function in use
   1033  *
   1034  * Provides the memory access functions set currently in use
   1035  *
   1036  * Returns 0 on success
   1037  */
   1038 int
   1039 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
   1040 	  xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
   1041     if (freeFunc != NULL) *freeFunc = xmlFree;
   1042     if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
   1043     if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
   1044     if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
   1045     return(0);
   1046 }
   1047 
   1048 /**
   1049  * xmlGcMemSetup:
   1050  * @freeFunc: the free() function to use
   1051  * @mallocFunc: the malloc() function to use
   1052  * @mallocAtomicFunc: the malloc() function to use for atomic allocations
   1053  * @reallocFunc: the realloc() function to use
   1054  * @strdupFunc: the strdup() function to use
   1055  *
   1056  * Override the default memory access functions with a new set
   1057  * This has to be called before any other libxml routines !
   1058  * The mallocAtomicFunc is specialized for atomic block
   1059  * allocations (i.e. of areas  useful for garbage collected memory allocators
   1060  *
   1061  * Should this be blocked if there was already some allocations
   1062  * done ?
   1063  *
   1064  * Returns 0 on success
   1065  */
   1066 int
   1067 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
   1068               xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc,
   1069 	      xmlStrdupFunc strdupFunc) {
   1070 #ifdef DEBUG_MEMORY
   1071      xmlGenericError(xmlGenericErrorContext,
   1072 	     "xmlGcMemSetup()\n");
   1073 #endif
   1074     if (freeFunc == NULL)
   1075 	return(-1);
   1076     if (mallocFunc == NULL)
   1077 	return(-1);
   1078     if (mallocAtomicFunc == NULL)
   1079 	return(-1);
   1080     if (reallocFunc == NULL)
   1081 	return(-1);
   1082     if (strdupFunc == NULL)
   1083 	return(-1);
   1084     xmlFree = freeFunc;
   1085     xmlMalloc = mallocFunc;
   1086     xmlMallocAtomic = mallocAtomicFunc;
   1087     xmlRealloc = reallocFunc;
   1088     xmlMemStrdup = strdupFunc;
   1089 #ifdef DEBUG_MEMORY
   1090      xmlGenericError(xmlGenericErrorContext,
   1091 	     "xmlGcMemSetup() Ok\n");
   1092 #endif
   1093     return(0);
   1094 }
   1095 
   1096 /**
   1097  * xmlGcMemGet:
   1098  * @freeFunc: place to save the free() function in use
   1099  * @mallocFunc: place to save the malloc() function in use
   1100  * @mallocAtomicFunc: place to save the atomic malloc() function in use
   1101  * @reallocFunc: place to save the realloc() function in use
   1102  * @strdupFunc: place to save the strdup() function in use
   1103  *
   1104  * Provides the memory access functions set currently in use
   1105  * The mallocAtomicFunc is specialized for atomic block
   1106  * allocations (i.e. of areas  useful for garbage collected memory allocators
   1107  *
   1108  * Returns 0 on success
   1109  */
   1110 int
   1111 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
   1112             xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc,
   1113 	    xmlStrdupFunc *strdupFunc) {
   1114     if (freeFunc != NULL) *freeFunc = xmlFree;
   1115     if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
   1116     if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic;
   1117     if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
   1118     if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
   1119     return(0);
   1120 }
   1121 
   1122 #define bottom_xmlmemory
   1123 #include "elfgcchack.h"
   1124