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 51static int xmlMemInitialized = 0; 52static unsigned long debugMemSize = 0; 53static unsigned long debugMemBlocks = 0; 54static unsigned long debugMaxMemSize = 0; 55static xmlMutexPtr xmlMemMutex = NULL; 56 57void 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 89typedef 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 117static unsigned int block=0; 118static unsigned int xmlMemStopAtBlock = 0; 119static void *xmlMemTraceBlockAt = NULL; 120#ifdef MEM_LIST 121static MEMHDR *memlist = NULL; 122#endif 123 124static void debugmem_tag_error(void *addr); 125#ifdef MEM_LIST 126static void debugmem_list_add(MEMHDR *); 127static 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 143void 144xmlMallocBreakpoint(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 160void * 161xmlMallocLoc(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 228void * 229xmlMallocAtomicLoc(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 293void * 294xmlMemMalloc(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 311void * 312xmlReallocLoc(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 378error: 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 392void * 393xmlMemRealloc(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 */ 403void 404xmlMemFree(void *ptr) 405{ 406 MEMHDR *p; 407 char *target; 408#ifdef DEBUG_MEMORY 409 size_t size; 410#endif 411 412 if (ptr == (void *) -1) { 413 xmlGenericError(xmlGenericErrorContext, 414 "trying to free pointer from freed area\n"); 415 goto error; 416 } 417 418 if (xmlMemTraceBlockAt == ptr) { 419 xmlGenericError(xmlGenericErrorContext, 420 "%p : Freed()\n", xmlMemTraceBlockAt); 421 xmlMallocBreakpoint(); 422 } 423 424 TEST_POINT 425 426 target = (char *) ptr; 427 428 p = CLIENT_2_HDR(ptr); 429 if (p->mh_tag != MEMTAG) { 430 Mem_Tag_Err(p); 431 goto error; 432 } 433 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); 434 p->mh_tag = ~MEMTAG; 435 memset(target, -1, p->mh_size); 436 xmlMutexLock(xmlMemMutex); 437 debugMemSize -= p->mh_size; 438 debugMemBlocks--; 439#ifdef DEBUG_MEMORY 440 size = p->mh_size; 441#endif 442#ifdef MEM_LIST 443 debugmem_list_delete(p); 444#endif 445 xmlMutexUnlock(xmlMemMutex); 446 447 free(p); 448 449 TEST_POINT 450 451#ifdef DEBUG_MEMORY 452 xmlGenericError(xmlGenericErrorContext, 453 "Freed(%d) Ok\n", size); 454#endif 455 456 return; 457 458error: 459 xmlGenericError(xmlGenericErrorContext, 460 "xmlMemFree(%lX) error\n", (unsigned long) ptr); 461 xmlMallocBreakpoint(); 462 return; 463} 464 465/** 466 * xmlMemStrdupLoc: 467 * @str: the initial string pointer 468 * @file: the file name or NULL 469 * @line: the line number 470 * 471 * a strdup() equivalent, with logging of the allocation info. 472 * 473 * Returns a pointer to the new string or NULL if allocation error occurred. 474 */ 475 476char * 477xmlMemStrdupLoc(const char *str, const char *file, int line) 478{ 479 char *s; 480 size_t size = strlen(str) + 1; 481 MEMHDR *p; 482 483 if (!xmlMemInitialized) xmlInitMemory(); 484 TEST_POINT 485 486 p = (MEMHDR *) malloc(RESERVE_SIZE+size); 487 if (!p) { 488 goto error; 489 } 490 p->mh_tag = MEMTAG; 491 p->mh_size = size; 492 p->mh_type = STRDUP_TYPE; 493 p->mh_file = file; 494 p->mh_line = line; 495 xmlMutexLock(xmlMemMutex); 496 p->mh_number = ++block; 497 debugMemSize += size; 498 debugMemBlocks++; 499 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; 500#ifdef MEM_LIST 501 debugmem_list_add(p); 502#endif 503 xmlMutexUnlock(xmlMemMutex); 504 505 s = (char *) HDR_2_CLIENT(p); 506 507 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); 508 509 if (s != NULL) 510 strcpy(s,str); 511 else 512 goto error; 513 514 TEST_POINT 515 516 if (xmlMemTraceBlockAt == s) { 517 xmlGenericError(xmlGenericErrorContext, 518 "%p : Strdup() Ok\n", xmlMemTraceBlockAt); 519 xmlMallocBreakpoint(); 520 } 521 522 return(s); 523 524error: 525 return(NULL); 526} 527 528/** 529 * xmlMemoryStrdup: 530 * @str: the initial string pointer 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 537char * 538xmlMemoryStrdup(const char *str) { 539 return(xmlMemStrdupLoc(str, "none", 0)); 540} 541 542/** 543 * xmlMemUsed: 544 * 545 * Provides the amount of memory currently allocated 546 * 547 * Returns an int representing the amount of memory allocated. 548 */ 549 550int 551xmlMemUsed(void) { 552 return(debugMemSize); 553} 554 555/** 556 * xmlMemBlocks: 557 * 558 * Provides the number of memory areas currently allocated 559 * 560 * Returns an int representing the number of blocks 561 */ 562 563int 564xmlMemBlocks(void) { 565 return(debugMemBlocks); 566} 567 568#ifdef MEM_LIST 569/** 570 * xmlMemContentShow: 571 * @fp: a FILE descriptor used as the output file 572 * @p: a memory block header 573 * 574 * tries to show some content from the memory block 575 */ 576 577static void 578xmlMemContentShow(FILE *fp, MEMHDR *p) 579{ 580 int i,j,len = p->mh_size; 581 const char *buf = (const char *) HDR_2_CLIENT(p); 582 583 if (p == NULL) { 584 fprintf(fp, " NULL"); 585 return; 586 } 587 588 for (i = 0;i < len;i++) { 589 if (buf[i] == 0) break; 590 if (!isprint((unsigned char) buf[i])) break; 591 } 592 if ((i < 4) && ((buf[i] != 0) || (i == 0))) { 593 if (len >= 4) { 594 MEMHDR *q; 595 void *cur; 596 597 for (j = 0;j < len -3;j += 4) { 598 cur = *((void **) &buf[j]); 599 q = CLIENT_2_HDR(cur); 600 p = memlist; 601 while (p != NULL) { 602 if (p == q) break; 603 p = p->mh_next; 604 } 605 if ((p != NULL) && (p == q)) { 606 fprintf(fp, " pointer to #%lu at index %d", 607 p->mh_number, j); 608 return; 609 } 610 } 611 } 612 } else if ((i == 0) && (buf[i] == 0)) { 613 fprintf(fp," null"); 614 } else { 615 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); 616 else { 617 fprintf(fp," ["); 618 for (j = 0;j < i;j++) 619 fprintf(fp,"%c", buf[j]); 620 fprintf(fp,"]"); 621 } 622 } 623} 624#endif 625 626/** 627 * xmlMemDisplay: 628 * @fp: a FILE descriptor used as the output file, if NULL, the result is 629 * written to the file .memorylist 630 * 631 * show in-extenso the memory blocks allocated 632 */ 633 634void 635xmlMemDisplay(FILE *fp) 636{ 637#ifdef MEM_LIST 638 MEMHDR *p; 639 unsigned idx; 640 int nb = 0; 641#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) 642 time_t currentTime; 643 char buf[500]; 644 struct tm * tstruct; 645#endif 646#endif 647 FILE *old_fp = fp; 648 649 if (fp == NULL) { 650 fp = fopen(".memorylist", "w"); 651 if (fp == NULL) 652 return; 653 } 654 655#ifdef MEM_LIST 656#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) 657 currentTime = time(NULL); 658 tstruct = localtime(¤tTime); 659 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct); 660 fprintf(fp," %s\n\n", buf); 661#endif 662 663 664 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", 665 debugMemSize, debugMaxMemSize); 666 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); 667 idx = 0; 668 xmlMutexLock(xmlMemMutex); 669 p = memlist; 670 while (p) { 671 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, 672 (unsigned long)p->mh_size); 673 switch (p->mh_type) { 674 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; 675 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; 676 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; 677 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; 678 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; 679 default: 680 fprintf(fp,"Unknown memory block, may be corrupted"); 681 xmlMutexUnlock(xmlMemMutex); 682 if (old_fp == NULL) 683 fclose(fp); 684 return; 685 } 686 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); 687 if (p->mh_tag != MEMTAG) 688 fprintf(fp," INVALID"); 689 nb++; 690 if (nb < 100) 691 xmlMemContentShow(fp, p); 692 else 693 fprintf(fp," skip"); 694 695 fprintf(fp,"\n"); 696 p = p->mh_next; 697 } 698 xmlMutexUnlock(xmlMemMutex); 699#else 700 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); 701#endif 702 if (old_fp == NULL) 703 fclose(fp); 704} 705 706#ifdef MEM_LIST 707 708static void debugmem_list_add(MEMHDR *p) 709{ 710 p->mh_next = memlist; 711 p->mh_prev = NULL; 712 if (memlist) memlist->mh_prev = p; 713 memlist = p; 714#ifdef MEM_LIST_DEBUG 715 if (stderr) 716 Mem_Display(stderr); 717#endif 718} 719 720static void debugmem_list_delete(MEMHDR *p) 721{ 722 if (p->mh_next) 723 p->mh_next->mh_prev = p->mh_prev; 724 if (p->mh_prev) 725 p->mh_prev->mh_next = p->mh_next; 726 else memlist = p->mh_next; 727#ifdef MEM_LIST_DEBUG 728 if (stderr) 729 Mem_Display(stderr); 730#endif 731} 732 733#endif 734 735/* 736 * debugmem_tag_error: 737 * 738 * internal error function. 739 */ 740 741static void debugmem_tag_error(void *p) 742{ 743 xmlGenericError(xmlGenericErrorContext, 744 "Memory tag error occurs :%p \n\t bye\n", p); 745#ifdef MEM_LIST 746 if (stderr) 747 xmlMemDisplay(stderr); 748#endif 749} 750 751#ifdef MEM_LIST 752static FILE *xmlMemoryDumpFile = NULL; 753#endif 754 755/** 756 * xmlMemShow: 757 * @fp: a FILE descriptor used as the output file 758 * @nr: number of entries to dump 759 * 760 * show a show display of the memory allocated, and dump 761 * the @nr last allocated areas which were not freed 762 */ 763 764void 765xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED) 766{ 767#ifdef MEM_LIST 768 MEMHDR *p; 769#endif 770 771 if (fp != NULL) 772 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", 773 debugMemSize, debugMaxMemSize); 774#ifdef MEM_LIST 775 xmlMutexLock(xmlMemMutex); 776 if (nr > 0) { 777 fprintf(fp,"NUMBER SIZE TYPE WHERE\n"); 778 p = memlist; 779 while ((p) && nr > 0) { 780 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size); 781 switch (p->mh_type) { 782 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; 783 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; 784 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; 785 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; 786 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; 787 default:fprintf(fp," ??? in ");break; 788 } 789 if (p->mh_file != NULL) 790 fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); 791 if (p->mh_tag != MEMTAG) 792 fprintf(fp," INVALID"); 793 xmlMemContentShow(fp, p); 794 fprintf(fp,"\n"); 795 nr--; 796 p = p->mh_next; 797 } 798 } 799 xmlMutexUnlock(xmlMemMutex); 800#endif /* MEM_LIST */ 801} 802 803/** 804 * xmlMemoryDump: 805 * 806 * Dump in-extenso the memory blocks allocated to the file .memorylist 807 */ 808 809void 810xmlMemoryDump(void) 811{ 812#ifdef MEM_LIST 813 FILE *dump; 814 815 if (debugMaxMemSize == 0) 816 return; 817 dump = fopen(".memdump", "w"); 818 if (dump == NULL) 819 xmlMemoryDumpFile = stderr; 820 else xmlMemoryDumpFile = dump; 821 822 xmlMemDisplay(xmlMemoryDumpFile); 823 824 if (dump != NULL) fclose(dump); 825#endif /* MEM_LIST */ 826} 827 828 829/**************************************************************** 830 * * 831 * Initialization Routines * 832 * * 833 ****************************************************************/ 834 835/** 836 * xmlInitMemory: 837 * 838 * Initialize the memory layer. 839 * 840 * Returns 0 on success 841 */ 842int 843xmlInitMemory(void) 844{ 845#ifdef HAVE_STDLIB_H 846 char *breakpoint; 847#endif 848#ifdef DEBUG_MEMORY 849 xmlGenericError(xmlGenericErrorContext, 850 "xmlInitMemory()\n"); 851#endif 852 /* 853 This is really not good code (see Bug 130419). Suggestions for 854 improvement will be welcome! 855 */ 856 if (xmlMemInitialized) return(-1); 857 xmlMemInitialized = 1; 858 xmlMemMutex = xmlNewMutex(); 859 860#ifdef HAVE_STDLIB_H 861 breakpoint = getenv("XML_MEM_BREAKPOINT"); 862 if (breakpoint != NULL) { 863 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock); 864 } 865#endif 866#ifdef HAVE_STDLIB_H 867 breakpoint = getenv("XML_MEM_TRACE"); 868 if (breakpoint != NULL) { 869 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt); 870 } 871#endif 872 873#ifdef DEBUG_MEMORY 874 xmlGenericError(xmlGenericErrorContext, 875 "xmlInitMemory() Ok\n"); 876#endif 877 return(0); 878} 879 880/** 881 * xmlCleanupMemory: 882 * 883 * Free up all the memory allocated by the library for its own 884 * use. This should not be called by user level code. 885 */ 886void 887xmlCleanupMemory(void) { 888#ifdef DEBUG_MEMORY 889 xmlGenericError(xmlGenericErrorContext, 890 "xmlCleanupMemory()\n"); 891#endif 892 if (xmlMemInitialized == 0) 893 return; 894 895 xmlFreeMutex(xmlMemMutex); 896 xmlMemMutex = NULL; 897 xmlMemInitialized = 0; 898#ifdef DEBUG_MEMORY 899 xmlGenericError(xmlGenericErrorContext, 900 "xmlCleanupMemory() Ok\n"); 901#endif 902} 903 904/** 905 * xmlMemSetup: 906 * @freeFunc: the free() function to use 907 * @mallocFunc: the malloc() function to use 908 * @reallocFunc: the realloc() function to use 909 * @strdupFunc: the strdup() function to use 910 * 911 * Override the default memory access functions with a new set 912 * This has to be called before any other libxml routines ! 913 * 914 * Should this be blocked if there was already some allocations 915 * done ? 916 * 917 * Returns 0 on success 918 */ 919int 920xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, 921 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) { 922#ifdef DEBUG_MEMORY 923 xmlGenericError(xmlGenericErrorContext, 924 "xmlMemSetup()\n"); 925#endif 926 if (freeFunc == NULL) 927 return(-1); 928 if (mallocFunc == NULL) 929 return(-1); 930 if (reallocFunc == NULL) 931 return(-1); 932 if (strdupFunc == NULL) 933 return(-1); 934 xmlFree = freeFunc; 935 xmlMalloc = mallocFunc; 936 xmlMallocAtomic = mallocFunc; 937 xmlRealloc = reallocFunc; 938 xmlMemStrdup = strdupFunc; 939#ifdef DEBUG_MEMORY 940 xmlGenericError(xmlGenericErrorContext, 941 "xmlMemSetup() Ok\n"); 942#endif 943 return(0); 944} 945 946/** 947 * xmlMemGet: 948 * @freeFunc: place to save the free() function in use 949 * @mallocFunc: place to save the malloc() function in use 950 * @reallocFunc: place to save the realloc() function in use 951 * @strdupFunc: place to save the strdup() function in use 952 * 953 * Provides the memory access functions set currently in use 954 * 955 * Returns 0 on success 956 */ 957int 958xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, 959 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) { 960 if (freeFunc != NULL) *freeFunc = xmlFree; 961 if (mallocFunc != NULL) *mallocFunc = xmlMalloc; 962 if (reallocFunc != NULL) *reallocFunc = xmlRealloc; 963 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; 964 return(0); 965} 966 967/** 968 * xmlGcMemSetup: 969 * @freeFunc: the free() function to use 970 * @mallocFunc: the malloc() function to use 971 * @mallocAtomicFunc: the malloc() function to use for atomic allocations 972 * @reallocFunc: the realloc() function to use 973 * @strdupFunc: the strdup() function to use 974 * 975 * Override the default memory access functions with a new set 976 * This has to be called before any other libxml routines ! 977 * The mallocAtomicFunc is specialized for atomic block 978 * allocations (i.e. of areas useful for garbage collected memory allocators 979 * 980 * Should this be blocked if there was already some allocations 981 * done ? 982 * 983 * Returns 0 on success 984 */ 985int 986xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, 987 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc, 988 xmlStrdupFunc strdupFunc) { 989#ifdef DEBUG_MEMORY 990 xmlGenericError(xmlGenericErrorContext, 991 "xmlGcMemSetup()\n"); 992#endif 993 if (freeFunc == NULL) 994 return(-1); 995 if (mallocFunc == NULL) 996 return(-1); 997 if (mallocAtomicFunc == NULL) 998 return(-1); 999 if (reallocFunc == NULL) 1000 return(-1); 1001 if (strdupFunc == NULL) 1002 return(-1); 1003 xmlFree = freeFunc; 1004 xmlMalloc = mallocFunc; 1005 xmlMallocAtomic = mallocAtomicFunc; 1006 xmlRealloc = reallocFunc; 1007 xmlMemStrdup = strdupFunc; 1008#ifdef DEBUG_MEMORY 1009 xmlGenericError(xmlGenericErrorContext, 1010 "xmlGcMemSetup() Ok\n"); 1011#endif 1012 return(0); 1013} 1014 1015/** 1016 * xmlGcMemGet: 1017 * @freeFunc: place to save the free() function in use 1018 * @mallocFunc: place to save the malloc() function in use 1019 * @mallocAtomicFunc: place to save the atomic malloc() function in use 1020 * @reallocFunc: place to save the realloc() function in use 1021 * @strdupFunc: place to save the strdup() function in use 1022 * 1023 * Provides the memory access functions set currently in use 1024 * The mallocAtomicFunc is specialized for atomic block 1025 * allocations (i.e. of areas useful for garbage collected memory allocators 1026 * 1027 * Returns 0 on success 1028 */ 1029int 1030xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, 1031 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc, 1032 xmlStrdupFunc *strdupFunc) { 1033 if (freeFunc != NULL) *freeFunc = xmlFree; 1034 if (mallocFunc != NULL) *mallocFunc = xmlMalloc; 1035 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic; 1036 if (reallocFunc != NULL) *reallocFunc = xmlRealloc; 1037 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; 1038 return(0); 1039} 1040 1041#define bottom_xmlmemory 1042#include "elfgcchack.h" 1043