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