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