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