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