xmlmemory.c
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(%lX) error\n", (unsigned long) 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 strncpy(s, str, size); 547 s[size - 1] = '\0'; 548 549 TEST_POINT 550 551 if (xmlMemTraceBlockAt == s) { 552 xmlGenericError(xmlGenericErrorContext, 553 "%p : Strdup() Ok\n", xmlMemTraceBlockAt); 554 xmlMallocBreakpoint(); 555 } 556 557 return(s); 558 559 error: 560 return(NULL); 561 } 562 563 /** 564 * xmlMemoryStrdup: 565 * @str: the initial string pointer 566 * 567 * a strdup() equivalent, with logging of the allocation info. 568 * 569 * Returns a pointer to the new string or NULL if allocation error occurred. 570 */ 571 572 char * 573 xmlMemoryStrdup(const char *str) { 574 return(xmlMemStrdupLoc(str, "none", 0)); 575 } 576 577 /** 578 * xmlMemUsed: 579 * 580 * Provides the amount of memory currently allocated 581 * 582 * Returns an int representing the amount of memory allocated. 583 */ 584 585 int 586 xmlMemUsed(void) { 587 int res; 588 589 xmlMutexLock(xmlMemMutex); 590 res = debugMemSize; 591 xmlMutexUnlock(xmlMemMutex); 592 return(res); 593 } 594 595 /** 596 * xmlMemBlocks: 597 * 598 * Provides the number of memory areas currently allocated 599 * 600 * Returns an int representing the number of blocks 601 */ 602 603 int 604 xmlMemBlocks(void) { 605 int res; 606 607 xmlMutexLock(xmlMemMutex); 608 res = debugMemBlocks; 609 xmlMutexUnlock(xmlMemMutex); 610 return(res); 611 } 612 613 #ifdef MEM_LIST 614 /** 615 * xmlMemContentShow: 616 * @fp: a FILE descriptor used as the output file 617 * @p: a memory block header 618 * 619 * tries to show some content from the memory block 620 */ 621 622 static void 623 xmlMemContentShow(FILE *fp, MEMHDR *p) 624 { 625 int i,j,k,len; 626 const char *buf; 627 628 if (p == NULL) { 629 fprintf(fp, " NULL"); 630 return; 631 } 632 len = p->mh_size; 633 buf = (const char *) HDR_2_CLIENT(p); 634 635 for (i = 0;i < len;i++) { 636 if (buf[i] == 0) break; 637 if (!isprint((unsigned char) buf[i])) break; 638 } 639 if ((i < 4) && ((buf[i] != 0) || (i == 0))) { 640 if (len >= 4) { 641 MEMHDR *q; 642 void *cur; 643 644 for (j = 0;(j < len -3) && (j < 40);j += 4) { 645 cur = *((void **) &buf[j]); 646 q = CLIENT_2_HDR(cur); 647 p = memlist; 648 k = 0; 649 while (p != NULL) { 650 if (p == q) break; 651 p = p->mh_next; 652 if (k++ > 100) break; 653 } 654 if ((p != NULL) && (p == q)) { 655 fprintf(fp, " pointer to #%lu at index %d", 656 p->mh_number, j); 657 return; 658 } 659 } 660 } 661 } else if ((i == 0) && (buf[i] == 0)) { 662 fprintf(fp," null"); 663 } else { 664 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); 665 else { 666 fprintf(fp," ["); 667 for (j = 0;j < i;j++) 668 fprintf(fp,"%c", buf[j]); 669 fprintf(fp,"]"); 670 } 671 } 672 } 673 #endif 674 675 /** 676 * xmlMemDisplayLast: 677 * @fp: a FILE descriptor used as the output file, if NULL, the result is 678 * written to the file .memorylist 679 * @nbBytes: the amount of memory to dump 680 * 681 * the last nbBytes of memory allocated and not freed, useful for dumping 682 * the memory left allocated between two places at runtime. 683 */ 684 685 void 686 xmlMemDisplayLast(FILE *fp, long nbBytes) 687 { 688 #ifdef MEM_LIST 689 MEMHDR *p; 690 unsigned idx; 691 int nb = 0; 692 #endif 693 FILE *old_fp = fp; 694 695 if (nbBytes <= 0) 696 return; 697 698 if (fp == NULL) { 699 fp = fopen(".memorylist", "w"); 700 if (fp == NULL) 701 return; 702 } 703 704 #ifdef MEM_LIST 705 fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n", 706 nbBytes, debugMemSize, debugMaxMemSize); 707 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); 708 idx = 0; 709 xmlMutexLock(xmlMemMutex); 710 p = memlist; 711 while ((p) && (nbBytes > 0)) { 712 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, 713 (unsigned long)p->mh_size); 714 switch (p->mh_type) { 715 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; 716 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; 717 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; 718 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; 719 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; 720 default: 721 fprintf(fp,"Unknown memory block, may be corrupted"); 722 xmlMutexUnlock(xmlMemMutex); 723 if (old_fp == NULL) 724 fclose(fp); 725 return; 726 } 727 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); 728 if (p->mh_tag != MEMTAG) 729 fprintf(fp," INVALID"); 730 nb++; 731 if (nb < 100) 732 xmlMemContentShow(fp, p); 733 else 734 fprintf(fp," skip"); 735 736 fprintf(fp,"\n"); 737 nbBytes -= (unsigned long)p->mh_size; 738 p = p->mh_next; 739 } 740 xmlMutexUnlock(xmlMemMutex); 741 #else 742 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); 743 #endif 744 if (old_fp == NULL) 745 fclose(fp); 746 } 747 748 /** 749 * xmlMemDisplay: 750 * @fp: a FILE descriptor used as the output file, if NULL, the result is 751 * written to the file .memorylist 752 * 753 * show in-extenso the memory blocks allocated 754 */ 755 756 void 757 xmlMemDisplay(FILE *fp) 758 { 759 #ifdef MEM_LIST 760 MEMHDR *p; 761 unsigned idx; 762 int nb = 0; 763 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) 764 time_t currentTime; 765 char buf[500]; 766 struct tm * tstruct; 767 #endif 768 #endif 769 FILE *old_fp = fp; 770 771 if (fp == NULL) { 772 fp = fopen(".memorylist", "w"); 773 if (fp == NULL) 774 return; 775 } 776 777 #ifdef MEM_LIST 778 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) 779 currentTime = time(NULL); 780 tstruct = localtime(¤tTime); 781 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct); 782 fprintf(fp," %s\n\n", buf); 783 #endif 784 785 786 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", 787 debugMemSize, debugMaxMemSize); 788 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); 789 idx = 0; 790 xmlMutexLock(xmlMemMutex); 791 p = memlist; 792 while (p) { 793 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, 794 (unsigned long)p->mh_size); 795 switch (p->mh_type) { 796 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; 797 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; 798 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; 799 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; 800 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; 801 default: 802 fprintf(fp,"Unknown memory block, may be corrupted"); 803 xmlMutexUnlock(xmlMemMutex); 804 if (old_fp == NULL) 805 fclose(fp); 806 return; 807 } 808 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); 809 if (p->mh_tag != MEMTAG) 810 fprintf(fp," INVALID"); 811 nb++; 812 if (nb < 100) 813 xmlMemContentShow(fp, p); 814 else 815 fprintf(fp," skip"); 816 817 fprintf(fp,"\n"); 818 p = p->mh_next; 819 } 820 xmlMutexUnlock(xmlMemMutex); 821 #else 822 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); 823 #endif 824 if (old_fp == NULL) 825 fclose(fp); 826 } 827 828 #ifdef MEM_LIST 829 830 static void debugmem_list_add(MEMHDR *p) 831 { 832 p->mh_next = memlist; 833 p->mh_prev = NULL; 834 if (memlist) memlist->mh_prev = p; 835 memlist = p; 836 #ifdef MEM_LIST_DEBUG 837 if (stderr) 838 Mem_Display(stderr); 839 #endif 840 } 841 842 static void debugmem_list_delete(MEMHDR *p) 843 { 844 if (p->mh_next) 845 p->mh_next->mh_prev = p->mh_prev; 846 if (p->mh_prev) 847 p->mh_prev->mh_next = p->mh_next; 848 else memlist = p->mh_next; 849 #ifdef MEM_LIST_DEBUG 850 if (stderr) 851 Mem_Display(stderr); 852 #endif 853 } 854 855 #endif 856 857 /* 858 * debugmem_tag_error: 859 * 860 * internal error function. 861 */ 862 863 static void debugmem_tag_error(void *p) 864 { 865 xmlGenericError(xmlGenericErrorContext, 866 "Memory tag error occurs :%p \n\t bye\n", p); 867 #ifdef MEM_LIST 868 if (stderr) 869 xmlMemDisplay(stderr); 870 #endif 871 } 872 873 #ifdef MEM_LIST 874 static FILE *xmlMemoryDumpFile = NULL; 875 #endif 876 877 /** 878 * xmlMemShow: 879 * @fp: a FILE descriptor used as the output file 880 * @nr: number of entries to dump 881 * 882 * show a show display of the memory allocated, and dump 883 * the @nr last allocated areas which were not freed 884 */ 885 886 void 887 xmlMemShow(FILE *fp, int nr ATTRIBUTE_UNUSED) 888 { 889 #ifdef MEM_LIST 890 MEMHDR *p; 891 #endif 892 893 if (fp != NULL) 894 fprintf(fp," MEMORY ALLOCATED : %lu, MAX was %lu\n", 895 debugMemSize, debugMaxMemSize); 896 #ifdef MEM_LIST 897 xmlMutexLock(xmlMemMutex); 898 if (nr > 0) { 899 fprintf(fp,"NUMBER SIZE TYPE WHERE\n"); 900 p = memlist; 901 while ((p) && nr > 0) { 902 fprintf(fp,"%6lu %6lu ",p->mh_number,(unsigned long)p->mh_size); 903 switch (p->mh_type) { 904 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; 905 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; 906 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; 907 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; 908 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; 909 default:fprintf(fp," ??? in ");break; 910 } 911 if (p->mh_file != NULL) 912 fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); 913 if (p->mh_tag != MEMTAG) 914 fprintf(fp," INVALID"); 915 xmlMemContentShow(fp, p); 916 fprintf(fp,"\n"); 917 nr--; 918 p = p->mh_next; 919 } 920 } 921 xmlMutexUnlock(xmlMemMutex); 922 #endif /* MEM_LIST */ 923 } 924 925 /** 926 * xmlMemoryDump: 927 * 928 * Dump in-extenso the memory blocks allocated to the file .memorylist 929 */ 930 931 void 932 xmlMemoryDump(void) 933 { 934 #ifdef MEM_LIST 935 FILE *dump; 936 937 if (debugMaxMemSize == 0) 938 return; 939 dump = fopen(".memdump", "w"); 940 if (dump == NULL) 941 xmlMemoryDumpFile = stderr; 942 else xmlMemoryDumpFile = dump; 943 944 xmlMemDisplay(xmlMemoryDumpFile); 945 946 if (dump != NULL) fclose(dump); 947 #endif /* MEM_LIST */ 948 } 949 950 951 /**************************************************************** 952 * * 953 * Initialization Routines * 954 * * 955 ****************************************************************/ 956 957 /** 958 * xmlInitMemory: 959 * 960 * Initialize the memory layer. 961 * 962 * Returns 0 on success 963 */ 964 int 965 xmlInitMemory(void) 966 { 967 #ifdef HAVE_STDLIB_H 968 char *breakpoint; 969 #endif 970 #ifdef DEBUG_MEMORY 971 xmlGenericError(xmlGenericErrorContext, 972 "xmlInitMemory()\n"); 973 #endif 974 /* 975 This is really not good code (see Bug 130419). Suggestions for 976 improvement will be welcome! 977 */ 978 if (xmlMemInitialized) return(-1); 979 xmlMemInitialized = 1; 980 xmlMemMutex = xmlNewMutex(); 981 982 #ifdef HAVE_STDLIB_H 983 breakpoint = getenv("XML_MEM_BREAKPOINT"); 984 if (breakpoint != NULL) { 985 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock); 986 } 987 #endif 988 #ifdef HAVE_STDLIB_H 989 breakpoint = getenv("XML_MEM_TRACE"); 990 if (breakpoint != NULL) { 991 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt); 992 } 993 #endif 994 995 #ifdef DEBUG_MEMORY 996 xmlGenericError(xmlGenericErrorContext, 997 "xmlInitMemory() Ok\n"); 998 #endif 999 return(0); 1000 } 1001 1002 /** 1003 * xmlCleanupMemory: 1004 * 1005 * Free up all the memory allocated by the library for its own 1006 * use. This should not be called by user level code. 1007 */ 1008 void 1009 xmlCleanupMemory(void) { 1010 #ifdef DEBUG_MEMORY 1011 xmlGenericError(xmlGenericErrorContext, 1012 "xmlCleanupMemory()\n"); 1013 #endif 1014 if (xmlMemInitialized == 0) 1015 return; 1016 1017 xmlFreeMutex(xmlMemMutex); 1018 xmlMemMutex = NULL; 1019 xmlMemInitialized = 0; 1020 #ifdef DEBUG_MEMORY 1021 xmlGenericError(xmlGenericErrorContext, 1022 "xmlCleanupMemory() Ok\n"); 1023 #endif 1024 } 1025 1026 /** 1027 * xmlMemSetup: 1028 * @freeFunc: the free() function to use 1029 * @mallocFunc: the malloc() function to use 1030 * @reallocFunc: the realloc() function to use 1031 * @strdupFunc: the strdup() function to use 1032 * 1033 * Override the default memory access functions with a new set 1034 * This has to be called before any other libxml routines ! 1035 * 1036 * Should this be blocked if there was already some allocations 1037 * done ? 1038 * 1039 * Returns 0 on success 1040 */ 1041 int 1042 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, 1043 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) { 1044 #ifdef DEBUG_MEMORY 1045 xmlGenericError(xmlGenericErrorContext, 1046 "xmlMemSetup()\n"); 1047 #endif 1048 if (freeFunc == NULL) 1049 return(-1); 1050 if (mallocFunc == NULL) 1051 return(-1); 1052 if (reallocFunc == NULL) 1053 return(-1); 1054 if (strdupFunc == NULL) 1055 return(-1); 1056 xmlFree = freeFunc; 1057 xmlMalloc = mallocFunc; 1058 xmlMallocAtomic = mallocFunc; 1059 xmlRealloc = reallocFunc; 1060 xmlMemStrdup = strdupFunc; 1061 #ifdef DEBUG_MEMORY 1062 xmlGenericError(xmlGenericErrorContext, 1063 "xmlMemSetup() Ok\n"); 1064 #endif 1065 return(0); 1066 } 1067 1068 /** 1069 * xmlMemGet: 1070 * @freeFunc: place to save the free() function in use 1071 * @mallocFunc: place to save the malloc() function in use 1072 * @reallocFunc: place to save the realloc() function in use 1073 * @strdupFunc: place to save the strdup() function in use 1074 * 1075 * Provides the memory access functions set currently in use 1076 * 1077 * Returns 0 on success 1078 */ 1079 int 1080 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, 1081 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) { 1082 if (freeFunc != NULL) *freeFunc = xmlFree; 1083 if (mallocFunc != NULL) *mallocFunc = xmlMalloc; 1084 if (reallocFunc != NULL) *reallocFunc = xmlRealloc; 1085 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; 1086 return(0); 1087 } 1088 1089 /** 1090 * xmlGcMemSetup: 1091 * @freeFunc: the free() function to use 1092 * @mallocFunc: the malloc() function to use 1093 * @mallocAtomicFunc: the malloc() function to use for atomic allocations 1094 * @reallocFunc: the realloc() function to use 1095 * @strdupFunc: the strdup() function to use 1096 * 1097 * Override the default memory access functions with a new set 1098 * This has to be called before any other libxml routines ! 1099 * The mallocAtomicFunc is specialized for atomic block 1100 * allocations (i.e. of areas useful for garbage collected memory allocators 1101 * 1102 * Should this be blocked if there was already some allocations 1103 * done ? 1104 * 1105 * Returns 0 on success 1106 */ 1107 int 1108 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, 1109 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc, 1110 xmlStrdupFunc strdupFunc) { 1111 #ifdef DEBUG_MEMORY 1112 xmlGenericError(xmlGenericErrorContext, 1113 "xmlGcMemSetup()\n"); 1114 #endif 1115 if (freeFunc == NULL) 1116 return(-1); 1117 if (mallocFunc == NULL) 1118 return(-1); 1119 if (mallocAtomicFunc == NULL) 1120 return(-1); 1121 if (reallocFunc == NULL) 1122 return(-1); 1123 if (strdupFunc == NULL) 1124 return(-1); 1125 xmlFree = freeFunc; 1126 xmlMalloc = mallocFunc; 1127 xmlMallocAtomic = mallocAtomicFunc; 1128 xmlRealloc = reallocFunc; 1129 xmlMemStrdup = strdupFunc; 1130 #ifdef DEBUG_MEMORY 1131 xmlGenericError(xmlGenericErrorContext, 1132 "xmlGcMemSetup() Ok\n"); 1133 #endif 1134 return(0); 1135 } 1136 1137 /** 1138 * xmlGcMemGet: 1139 * @freeFunc: place to save the free() function in use 1140 * @mallocFunc: place to save the malloc() function in use 1141 * @mallocAtomicFunc: place to save the atomic malloc() function in use 1142 * @reallocFunc: place to save the realloc() function in use 1143 * @strdupFunc: place to save the strdup() function in use 1144 * 1145 * Provides the memory access functions set currently in use 1146 * The mallocAtomicFunc is specialized for atomic block 1147 * allocations (i.e. of areas useful for garbage collected memory allocators 1148 * 1149 * Returns 0 on success 1150 */ 1151 int 1152 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, 1153 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc, 1154 xmlStrdupFunc *strdupFunc) { 1155 if (freeFunc != NULL) *freeFunc = xmlFree; 1156 if (mallocFunc != NULL) *mallocFunc = xmlMalloc; 1157 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic; 1158 if (reallocFunc != NULL) *reallocFunc = xmlRealloc; 1159 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; 1160 return(0); 1161 } 1162 1163 #define bottom_xmlmemory 1164 #include "elfgcchack.h"