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,k,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 < 40);j += 4) { 598 cur = *((void **) &buf[j]); 599 q = CLIENT_2_HDR(cur); 600 p = memlist; 601 k = 0; 602 while (p != NULL) { 603 if (p == q) break; 604 p = p->mh_next; 605 if (k++ > 100) break; 606 } 607 if ((p != NULL) && (p == q)) { 608 fprintf(fp, " pointer to #%lu at index %d", 609 p->mh_number, j); 610 return; 611 } 612 } 613 } 614 } else if ((i == 0) && (buf[i] == 0)) { 615 fprintf(fp," null"); 616 } else { 617 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); 618 else { 619 fprintf(fp," ["); 620 for (j = 0;j < i;j++) 621 fprintf(fp,"%c", buf[j]); 622 fprintf(fp,"]"); 623 } 624 } 625} 626#endif 627 628/** 629 * xmlMemDisplay: 630 * @fp: a FILE descriptor used as the output file, if NULL, the result is 631 * written to the file .memorylist 632 * 633 * show in-extenso the memory blocks allocated 634 */ 635 636void 637xmlMemDisplay(FILE *fp) 638{ 639#ifdef MEM_LIST 640 MEMHDR *p; 641 unsigned idx; 642 int nb = 0; 643#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) 644 time_t currentTime; 645 char buf[500]; 646 struct tm * tstruct; 647#endif 648#endif 649 FILE *old_fp = fp; 650 651 if (fp == NULL) { 652 fp = fopen(".memorylist", "w"); 653 if (fp == NULL) 654 return; 655 } 656 657#ifdef MEM_LIST 658#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) 659 currentTime = time(NULL); 660 tstruct = localtime(¤tTime); 661 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct); 662 fprintf(fp," %s\n\n", buf); 663#endif 664 665 666 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", 667 debugMemSize, debugMaxMemSize); 668 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); 669 idx = 0; 670 xmlMutexLock(xmlMemMutex); 671 p = memlist; 672 while (p) { 673 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, 674 (unsigned long)p->mh_size); 675 switch (p->mh_type) { 676 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; 677 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; 678 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; 679 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; 680 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; 681 default: 682 fprintf(fp,"Unknown memory block, may be corrupted"); 683 xmlMutexUnlock(xmlMemMutex); 684 if (old_fp == NULL) 685 fclose(fp); 686 return; 687 } 688 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); 689 if (p->mh_tag != MEMTAG) 690 fprintf(fp," INVALID"); 691 nb++; 692 if (nb < 100) 693 xmlMemContentShow(fp, p); 694 else 695 fprintf(fp," skip"); 696 697 fprintf(fp,"\n"); 698 p = p->mh_next; 699 } 700 xmlMutexUnlock(xmlMemMutex); 701#else 702 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); 703#endif 704 if (old_fp == NULL) 705 fclose(fp); 706} 707 708#ifdef MEM_LIST 709 710static void debugmem_list_add(MEMHDR *p) 711{ 712 p->mh_next = memlist; 713 p->mh_prev = NULL; 714 if (memlist) memlist->mh_prev = p; 715 memlist = p; 716#ifdef MEM_LIST_DEBUG 717 if (stderr) 718 Mem_Display(stderr); 719#endif 720} 721 722static void debugmem_list_delete(MEMHDR *p) 723{ 724 if (p->mh_next) 725 p->mh_next->mh_prev = p->mh_prev; 726 if (p->mh_prev) 727 p->mh_prev->mh_next = p->mh_next; 728 else memlist = p->mh_next; 729#ifdef MEM_LIST_DEBUG 730 if (stderr) 731 Mem_Display(stderr); 732#endif 733} 734 735#endif 736 737/* 738 * debugmem_tag_error: 739 * 740 * internal error function. 741 */ 742 743static void debugmem_tag_error(void *p) 744{ 745 xmlGenericError(xmlGenericErrorContext, 746 "Memory tag error occurs :%p \n\t bye\n", p); 747#ifdef MEM_LIST 748 if (stderr) 749 xmlMemDisplay(stderr); 750#endif 751} 752 753#ifdef MEM_LIST 754static FILE *xmlMemoryDumpFile = NULL; 755#endif 756 757/** 758 * xmlMemShow: 759 * @fp: a FILE descriptor used as the output file 760 * @nr: number of entries to dump 761 * 762 * show a show display of the memory allocated, and dump 763 * the @nr last allocated areas which were not freed 764 */ 765 766void 767xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED) 768{ 769#ifdef MEM_LIST 770 MEMHDR *p; 771#endif 772 773 if (fp != NULL) 774 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", 775 debugMemSize, debugMaxMemSize); 776#ifdef MEM_LIST 777 xmlMutexLock(xmlMemMutex); 778 if (nr > 0) { 779 fprintf(fp,"NUMBER SIZE TYPE WHERE\n"); 780 p = memlist; 781 while ((p) && nr > 0) { 782 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size); 783 switch (p->mh_type) { 784 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; 785 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; 786 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; 787 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; 788 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; 789 default:fprintf(fp," ??? in ");break; 790 } 791 if (p->mh_file != NULL) 792 fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); 793 if (p->mh_tag != MEMTAG) 794 fprintf(fp," INVALID"); 795 xmlMemContentShow(fp, p); 796 fprintf(fp,"\n"); 797 nr--; 798 p = p->mh_next; 799 } 800 } 801 xmlMutexUnlock(xmlMemMutex); 802#endif /* MEM_LIST */ 803} 804 805/** 806 * xmlMemoryDump: 807 * 808 * Dump in-extenso the memory blocks allocated to the file .memorylist 809 */ 810 811void 812xmlMemoryDump(void) 813{ 814#ifdef MEM_LIST 815 FILE *dump; 816 817 if (debugMaxMemSize == 0) 818 return; 819 dump = fopen(".memdump", "w"); 820 if (dump == NULL) 821 xmlMemoryDumpFile = stderr; 822 else xmlMemoryDumpFile = dump; 823 824 xmlMemDisplay(xmlMemoryDumpFile); 825 826 if (dump != NULL) fclose(dump); 827#endif /* MEM_LIST */ 828} 829 830 831/**************************************************************** 832 * * 833 * Initialization Routines * 834 * * 835 ****************************************************************/ 836 837/** 838 * xmlInitMemory: 839 * 840 * Initialize the memory layer. 841 * 842 * Returns 0 on success 843 */ 844int 845xmlInitMemory(void) 846{ 847#ifdef HAVE_STDLIB_H 848 char *breakpoint; 849#endif 850#ifdef DEBUG_MEMORY 851 xmlGenericError(xmlGenericErrorContext, 852 "xmlInitMemory()\n"); 853#endif 854 /* 855 This is really not good code (see Bug 130419). Suggestions for 856 improvement will be welcome! 857 */ 858 if (xmlMemInitialized) return(-1); 859 xmlMemInitialized = 1; 860 xmlMemMutex = xmlNewMutex(); 861 862#ifdef HAVE_STDLIB_H 863 breakpoint = getenv("XML_MEM_BREAKPOINT"); 864 if (breakpoint != NULL) { 865 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock); 866 } 867#endif 868#ifdef HAVE_STDLIB_H 869 breakpoint = getenv("XML_MEM_TRACE"); 870 if (breakpoint != NULL) { 871 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt); 872 } 873#endif 874 875#ifdef DEBUG_MEMORY 876 xmlGenericError(xmlGenericErrorContext, 877 "xmlInitMemory() Ok\n"); 878#endif 879 return(0); 880} 881 882/** 883 * xmlCleanupMemory: 884 * 885 * Free up all the memory allocated by the library for its own 886 * use. This should not be called by user level code. 887 */ 888void 889xmlCleanupMemory(void) { 890#ifdef DEBUG_MEMORY 891 xmlGenericError(xmlGenericErrorContext, 892 "xmlCleanupMemory()\n"); 893#endif 894 if (xmlMemInitialized == 0) 895 return; 896 897 xmlFreeMutex(xmlMemMutex); 898 xmlMemMutex = NULL; 899 xmlMemInitialized = 0; 900#ifdef DEBUG_MEMORY 901 xmlGenericError(xmlGenericErrorContext, 902 "xmlCleanupMemory() Ok\n"); 903#endif 904} 905 906/** 907 * xmlMemSetup: 908 * @freeFunc: the free() function to use 909 * @mallocFunc: the malloc() function to use 910 * @reallocFunc: the realloc() function to use 911 * @strdupFunc: the strdup() function to use 912 * 913 * Override the default memory access functions with a new set 914 * This has to be called before any other libxml routines ! 915 * 916 * Should this be blocked if there was already some allocations 917 * done ? 918 * 919 * Returns 0 on success 920 */ 921int 922xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, 923 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) { 924#ifdef DEBUG_MEMORY 925 xmlGenericError(xmlGenericErrorContext, 926 "xmlMemSetup()\n"); 927#endif 928 if (freeFunc == NULL) 929 return(-1); 930 if (mallocFunc == NULL) 931 return(-1); 932 if (reallocFunc == NULL) 933 return(-1); 934 if (strdupFunc == NULL) 935 return(-1); 936 xmlFree = freeFunc; 937 xmlMalloc = mallocFunc; 938 xmlMallocAtomic = mallocFunc; 939 xmlRealloc = reallocFunc; 940 xmlMemStrdup = strdupFunc; 941#ifdef DEBUG_MEMORY 942 xmlGenericError(xmlGenericErrorContext, 943 "xmlMemSetup() Ok\n"); 944#endif 945 return(0); 946} 947 948/** 949 * xmlMemGet: 950 * @freeFunc: place to save the free() function in use 951 * @mallocFunc: place to save the malloc() function in use 952 * @reallocFunc: place to save the realloc() function in use 953 * @strdupFunc: place to save the strdup() function in use 954 * 955 * Provides the memory access functions set currently in use 956 * 957 * Returns 0 on success 958 */ 959int 960xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, 961 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) { 962 if (freeFunc != NULL) *freeFunc = xmlFree; 963 if (mallocFunc != NULL) *mallocFunc = xmlMalloc; 964 if (reallocFunc != NULL) *reallocFunc = xmlRealloc; 965 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; 966 return(0); 967} 968 969/** 970 * xmlGcMemSetup: 971 * @freeFunc: the free() function to use 972 * @mallocFunc: the malloc() function to use 973 * @mallocAtomicFunc: the malloc() function to use for atomic allocations 974 * @reallocFunc: the realloc() function to use 975 * @strdupFunc: the strdup() function to use 976 * 977 * Override the default memory access functions with a new set 978 * This has to be called before any other libxml routines ! 979 * The mallocAtomicFunc is specialized for atomic block 980 * allocations (i.e. of areas useful for garbage collected memory allocators 981 * 982 * Should this be blocked if there was already some allocations 983 * done ? 984 * 985 * Returns 0 on success 986 */ 987int 988xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, 989 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc, 990 xmlStrdupFunc strdupFunc) { 991#ifdef DEBUG_MEMORY 992 xmlGenericError(xmlGenericErrorContext, 993 "xmlGcMemSetup()\n"); 994#endif 995 if (freeFunc == NULL) 996 return(-1); 997 if (mallocFunc == NULL) 998 return(-1); 999 if (mallocAtomicFunc == NULL) 1000 return(-1); 1001 if (reallocFunc == NULL) 1002 return(-1); 1003 if (strdupFunc == NULL) 1004 return(-1); 1005 xmlFree = freeFunc; 1006 xmlMalloc = mallocFunc; 1007 xmlMallocAtomic = mallocAtomicFunc; 1008 xmlRealloc = reallocFunc; 1009 xmlMemStrdup = strdupFunc; 1010#ifdef DEBUG_MEMORY 1011 xmlGenericError(xmlGenericErrorContext, 1012 "xmlGcMemSetup() Ok\n"); 1013#endif 1014 return(0); 1015} 1016 1017/** 1018 * xmlGcMemGet: 1019 * @freeFunc: place to save the free() function in use 1020 * @mallocFunc: place to save the malloc() function in use 1021 * @mallocAtomicFunc: place to save the atomic malloc() function in use 1022 * @reallocFunc: place to save the realloc() function in use 1023 * @strdupFunc: place to save the strdup() function in use 1024 * 1025 * Provides the memory access functions set currently in use 1026 * The mallocAtomicFunc is specialized for atomic block 1027 * allocations (i.e. of areas useful for garbage collected memory allocators 1028 * 1029 * Returns 0 on success 1030 */ 1031int 1032xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, 1033 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc, 1034 xmlStrdupFunc *strdupFunc) { 1035 if (freeFunc != NULL) *freeFunc = xmlFree; 1036 if (mallocFunc != NULL) *mallocFunc = xmlMalloc; 1037 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic; 1038 if (reallocFunc != NULL) *reallocFunc = xmlRealloc; 1039 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; 1040 return(0); 1041} 1042 1043#define bottom_xmlmemory 1044#include "elfgcchack.h" 1045