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