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