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