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