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