1 /* 2 * xmlmemory.c: libxml memory allocator wrapper. 3 * 4 * daniel (at) 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) ((MEMHDR *) (((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 p = (MEMHDR *) malloc(RESERVE_SIZE+size); 176 177 if (!p) { 178 xmlGenericError(xmlGenericErrorContext, 179 "xmlMallocLoc : Out of free space\n"); 180 xmlMemoryDump(); 181 return(NULL); 182 } 183 p->mh_tag = MEMTAG; 184 p->mh_size = size; 185 p->mh_type = MALLOC_TYPE; 186 p->mh_file = file; 187 p->mh_line = line; 188 xmlMutexLock(xmlMemMutex); 189 p->mh_number = ++block; 190 debugMemSize += size; 191 debugMemBlocks++; 192 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; 193 #ifdef MEM_LIST 194 debugmem_list_add(p); 195 #endif 196 xmlMutexUnlock(xmlMemMutex); 197 198 #ifdef DEBUG_MEMORY 199 xmlGenericError(xmlGenericErrorContext, 200 "Malloc(%d) Ok\n",size); 201 #endif 202 203 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); 204 205 ret = HDR_2_CLIENT(p); 206 207 if (xmlMemTraceBlockAt == ret) { 208 xmlGenericError(xmlGenericErrorContext, 209 "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt, 210 (long unsigned)size); 211 xmlMallocBreakpoint(); 212 } 213 214 TEST_POINT 215 216 return(ret); 217 } 218 219 /** 220 * xmlMallocAtomicLoc: 221 * @size: an unsigned int specifying the size in byte to allocate. 222 * @file: the file name or NULL 223 * @line: the line number 224 * 225 * a malloc() equivalent, with logging of the allocation info. 226 * 227 * Returns a pointer to the allocated area or NULL in case of lack of memory. 228 */ 229 230 void * 231 xmlMallocAtomicLoc(size_t size, const char * file, int line) 232 { 233 MEMHDR *p; 234 void *ret; 235 236 if (!xmlMemInitialized) xmlInitMemory(); 237 #ifdef DEBUG_MEMORY 238 xmlGenericError(xmlGenericErrorContext, 239 "Malloc(%d)\n",size); 240 #endif 241 242 TEST_POINT 243 244 if (size > (MAX_SIZE_T - RESERVE_SIZE)) { 245 xmlGenericError(xmlGenericErrorContext, 246 "xmlMallocAtomicLoc : Unsigned overflow prevented\n"); 247 xmlMemoryDump(); 248 return(NULL); 249 } 250 251 p = (MEMHDR *) malloc(RESERVE_SIZE+size); 252 253 if (!p) { 254 xmlGenericError(xmlGenericErrorContext, 255 "xmlMallocAtomicLoc : Out of free space\n"); 256 xmlMemoryDump(); 257 return(NULL); 258 } 259 p->mh_tag = MEMTAG; 260 p->mh_size = size; 261 p->mh_type = MALLOC_ATOMIC_TYPE; 262 p->mh_file = file; 263 p->mh_line = line; 264 xmlMutexLock(xmlMemMutex); 265 p->mh_number = ++block; 266 debugMemSize += size; 267 debugMemBlocks++; 268 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; 269 #ifdef MEM_LIST 270 debugmem_list_add(p); 271 #endif 272 xmlMutexUnlock(xmlMemMutex); 273 274 #ifdef DEBUG_MEMORY 275 xmlGenericError(xmlGenericErrorContext, 276 "Malloc(%d) Ok\n",size); 277 #endif 278 279 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); 280 281 ret = HDR_2_CLIENT(p); 282 283 if (xmlMemTraceBlockAt == ret) { 284 xmlGenericError(xmlGenericErrorContext, 285 "%p : Malloc(%lu) Ok\n", xmlMemTraceBlockAt, 286 (long unsigned)size); 287 xmlMallocBreakpoint(); 288 } 289 290 TEST_POINT 291 292 return(ret); 293 } 294 /** 295 * xmlMemMalloc: 296 * @size: an int specifying the size in byte to allocate. 297 * 298 * a malloc() equivalent, with logging of the allocation info. 299 * 300 * Returns a pointer to the allocated area or NULL in case of lack of memory. 301 */ 302 303 void * 304 xmlMemMalloc(size_t size) 305 { 306 return(xmlMallocLoc(size, "none", 0)); 307 } 308 309 /** 310 * xmlReallocLoc: 311 * @ptr: the initial memory block pointer 312 * @size: an int specifying the size in byte to allocate. 313 * @file: the file name or NULL 314 * @line: the line number 315 * 316 * a realloc() equivalent, with logging of the allocation info. 317 * 318 * Returns a pointer to the allocated area or NULL in case of lack of memory. 319 */ 320 321 void * 322 xmlReallocLoc(void *ptr,size_t size, const char * file, int line) 323 { 324 MEMHDR *p, *tmp; 325 unsigned long number; 326 #ifdef DEBUG_MEMORY 327 size_t oldsize; 328 #endif 329 330 if (ptr == NULL) 331 return(xmlMallocLoc(size, file, line)); 332 333 if (!xmlMemInitialized) xmlInitMemory(); 334 TEST_POINT 335 336 p = CLIENT_2_HDR(ptr); 337 number = p->mh_number; 338 if (xmlMemStopAtBlock == number) xmlMallocBreakpoint(); 339 if (p->mh_tag != MEMTAG) { 340 Mem_Tag_Err(p); 341 goto error; 342 } 343 p->mh_tag = ~MEMTAG; 344 xmlMutexLock(xmlMemMutex); 345 debugMemSize -= p->mh_size; 346 debugMemBlocks--; 347 #ifdef DEBUG_MEMORY 348 oldsize = p->mh_size; 349 #endif 350 #ifdef MEM_LIST 351 debugmem_list_delete(p); 352 #endif 353 xmlMutexUnlock(xmlMemMutex); 354 355 tmp = (MEMHDR *) realloc(p,RESERVE_SIZE+size); 356 if (!tmp) { 357 free(p); 358 goto error; 359 } 360 p = tmp; 361 if (xmlMemTraceBlockAt == ptr) { 362 xmlGenericError(xmlGenericErrorContext, 363 "%p : Realloced(%lu -> %lu) Ok\n", 364 xmlMemTraceBlockAt, (long unsigned)p->mh_size, 365 (long unsigned)size); 366 xmlMallocBreakpoint(); 367 } 368 p->mh_tag = MEMTAG; 369 p->mh_number = number; 370 p->mh_type = REALLOC_TYPE; 371 p->mh_size = size; 372 p->mh_file = file; 373 p->mh_line = line; 374 xmlMutexLock(xmlMemMutex); 375 debugMemSize += size; 376 debugMemBlocks++; 377 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; 378 #ifdef MEM_LIST 379 debugmem_list_add(p); 380 #endif 381 xmlMutexUnlock(xmlMemMutex); 382 383 TEST_POINT 384 385 #ifdef DEBUG_MEMORY 386 xmlGenericError(xmlGenericErrorContext, 387 "Realloced(%d to %d) Ok\n", oldsize, size); 388 #endif 389 return(HDR_2_CLIENT(p)); 390 391 error: 392 return(NULL); 393 } 394 395 /** 396 * xmlMemRealloc: 397 * @ptr: the initial memory block pointer 398 * @size: an int specifying the size in byte to allocate. 399 * 400 * a realloc() equivalent, with logging of the allocation info. 401 * 402 * Returns a pointer to the allocated area or NULL in case of lack of memory. 403 */ 404 405 void * 406 xmlMemRealloc(void *ptr,size_t size) { 407 return(xmlReallocLoc(ptr, size, "none", 0)); 408 } 409 410 /** 411 * xmlMemFree: 412 * @ptr: the memory block pointer 413 * 414 * a free() equivalent, with error checking. 415 */ 416 void 417 xmlMemFree(void *ptr) 418 { 419 MEMHDR *p; 420 char *target; 421 #ifdef DEBUG_MEMORY 422 size_t size; 423 #endif 424 425 if (ptr == NULL) 426 return; 427 428 if (ptr == (void *) -1) { 429 xmlGenericError(xmlGenericErrorContext, 430 "trying to free pointer from freed area\n"); 431 goto error; 432 } 433 434 if (xmlMemTraceBlockAt == ptr) { 435 xmlGenericError(xmlGenericErrorContext, 436 "%p : Freed()\n", xmlMemTraceBlockAt); 437 xmlMallocBreakpoint(); 438 } 439 440 TEST_POINT 441 442 target = (char *) ptr; 443 444 p = CLIENT_2_HDR(ptr); 445 if (p->mh_tag != MEMTAG) { 446 Mem_Tag_Err(p); 447 goto error; 448 } 449 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); 450 p->mh_tag = ~MEMTAG; 451 memset(target, -1, p->mh_size); 452 xmlMutexLock(xmlMemMutex); 453 debugMemSize -= p->mh_size; 454 debugMemBlocks--; 455 #ifdef DEBUG_MEMORY 456 size = p->mh_size; 457 #endif 458 #ifdef MEM_LIST 459 debugmem_list_delete(p); 460 #endif 461 xmlMutexUnlock(xmlMemMutex); 462 463 free(p); 464 465 TEST_POINT 466 467 #ifdef DEBUG_MEMORY 468 xmlGenericError(xmlGenericErrorContext, 469 "Freed(%d) Ok\n", size); 470 #endif 471 472 return; 473 474 error: 475 xmlGenericError(xmlGenericErrorContext, 476 "xmlMemFree(%lX) error\n", (unsigned long) ptr); 477 xmlMallocBreakpoint(); 478 return; 479 } 480 481 /** 482 * xmlMemStrdupLoc: 483 * @str: the initial string pointer 484 * @file: the file name or NULL 485 * @line: the line number 486 * 487 * a strdup() equivalent, with logging of the allocation info. 488 * 489 * Returns a pointer to the new string or NULL if allocation error occurred. 490 */ 491 492 char * 493 xmlMemStrdupLoc(const char *str, const char *file, int line) 494 { 495 char *s; 496 size_t size = strlen(str) + 1; 497 MEMHDR *p; 498 499 if (!xmlMemInitialized) xmlInitMemory(); 500 TEST_POINT 501 502 p = (MEMHDR *) malloc(RESERVE_SIZE+size); 503 if (!p) { 504 goto error; 505 } 506 p->mh_tag = MEMTAG; 507 p->mh_size = size; 508 p->mh_type = STRDUP_TYPE; 509 p->mh_file = file; 510 p->mh_line = line; 511 xmlMutexLock(xmlMemMutex); 512 p->mh_number = ++block; 513 debugMemSize += size; 514 debugMemBlocks++; 515 if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize; 516 #ifdef MEM_LIST 517 debugmem_list_add(p); 518 #endif 519 xmlMutexUnlock(xmlMemMutex); 520 521 s = (char *) HDR_2_CLIENT(p); 522 523 if (xmlMemStopAtBlock == p->mh_number) xmlMallocBreakpoint(); 524 525 strcpy(s,str); 526 527 TEST_POINT 528 529 if (xmlMemTraceBlockAt == s) { 530 xmlGenericError(xmlGenericErrorContext, 531 "%p : Strdup() Ok\n", xmlMemTraceBlockAt); 532 xmlMallocBreakpoint(); 533 } 534 535 return(s); 536 537 error: 538 return(NULL); 539 } 540 541 /** 542 * xmlMemoryStrdup: 543 * @str: the initial string pointer 544 * 545 * a strdup() equivalent, with logging of the allocation info. 546 * 547 * Returns a pointer to the new string or NULL if allocation error occurred. 548 */ 549 550 char * 551 xmlMemoryStrdup(const char *str) { 552 return(xmlMemStrdupLoc(str, "none", 0)); 553 } 554 555 /** 556 * xmlMemUsed: 557 * 558 * Provides the amount of memory currently allocated 559 * 560 * Returns an int representing the amount of memory allocated. 561 */ 562 563 int 564 xmlMemUsed(void) { 565 int res; 566 567 xmlMutexLock(xmlMemMutex); 568 res = debugMemSize; 569 xmlMutexUnlock(xmlMemMutex); 570 return(res); 571 } 572 573 /** 574 * xmlMemBlocks: 575 * 576 * Provides the number of memory areas currently allocated 577 * 578 * Returns an int representing the number of blocks 579 */ 580 581 int 582 xmlMemBlocks(void) { 583 int res; 584 585 xmlMutexLock(xmlMemMutex); 586 res = debugMemBlocks; 587 xmlMutexUnlock(xmlMemMutex); 588 return(res); 589 } 590 591 #ifdef MEM_LIST 592 /** 593 * xmlMemContentShow: 594 * @fp: a FILE descriptor used as the output file 595 * @p: a memory block header 596 * 597 * tries to show some content from the memory block 598 */ 599 600 static void 601 xmlMemContentShow(FILE *fp, MEMHDR *p) 602 { 603 int i,j,k,len; 604 const char *buf; 605 606 if (p == NULL) { 607 fprintf(fp, " NULL"); 608 return; 609 } 610 len = p->mh_size; 611 buf = (const char *) HDR_2_CLIENT(p); 612 613 for (i = 0;i < len;i++) { 614 if (buf[i] == 0) break; 615 if (!isprint((unsigned char) buf[i])) break; 616 } 617 if ((i < 4) && ((buf[i] != 0) || (i == 0))) { 618 if (len >= 4) { 619 MEMHDR *q; 620 void *cur; 621 622 for (j = 0;(j < len -3) && (j < 40);j += 4) { 623 cur = *((void **) &buf[j]); 624 q = CLIENT_2_HDR(cur); 625 p = memlist; 626 k = 0; 627 while (p != NULL) { 628 if (p == q) break; 629 p = p->mh_next; 630 if (k++ > 100) break; 631 } 632 if ((p != NULL) && (p == q)) { 633 fprintf(fp, " pointer to #%lu at index %d", 634 p->mh_number, j); 635 return; 636 } 637 } 638 } 639 } else if ((i == 0) && (buf[i] == 0)) { 640 fprintf(fp," null"); 641 } else { 642 if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); 643 else { 644 fprintf(fp," ["); 645 for (j = 0;j < i;j++) 646 fprintf(fp,"%c", buf[j]); 647 fprintf(fp,"]"); 648 } 649 } 650 } 651 #endif 652 653 /** 654 * xmlMemDisplayLast: 655 * @fp: a FILE descriptor used as the output file, if NULL, the result is 656 * written to the file .memorylist 657 * @nbBytes: the amount of memory to dump 658 * 659 * the last nbBytes of memory allocated and not freed, useful for dumping 660 * the memory left allocated between two places at runtime. 661 */ 662 663 void 664 xmlMemDisplayLast(FILE *fp, long nbBytes) 665 { 666 #ifdef MEM_LIST 667 MEMHDR *p; 668 unsigned idx; 669 int nb = 0; 670 #endif 671 FILE *old_fp = fp; 672 673 if (nbBytes <= 0) 674 return; 675 676 if (fp == NULL) { 677 fp = fopen(".memorylist", "w"); 678 if (fp == NULL) 679 return; 680 } 681 682 #ifdef MEM_LIST 683 fprintf(fp," Last %li MEMORY ALLOCATED : %lu, MAX was %lu\n", 684 nbBytes, debugMemSize, debugMaxMemSize); 685 fprintf(fp,"BLOCK NUMBER SIZE TYPE\n"); 686 idx = 0; 687 xmlMutexLock(xmlMemMutex); 688 p = memlist; 689 while ((p) && (nbBytes > 0)) { 690 fprintf(fp,"%-5u %6lu %6lu ",idx++,p->mh_number, 691 (unsigned long)p->mh_size); 692 switch (p->mh_type) { 693 case STRDUP_TYPE:fprintf(fp,"strdup() in ");break; 694 case MALLOC_TYPE:fprintf(fp,"malloc() in ");break; 695 case REALLOC_TYPE:fprintf(fp,"realloc() in ");break; 696 case MALLOC_ATOMIC_TYPE:fprintf(fp,"atomicmalloc() in ");break; 697 case REALLOC_ATOMIC_TYPE:fprintf(fp,"atomicrealloc() in ");break; 698 default: 699 fprintf(fp,"Unknown memory block, may be corrupted"); 700 xmlMutexUnlock(xmlMemMutex); 701 if (old_fp == NULL) 702 fclose(fp); 703 return; 704 } 705 if (p->mh_file != NULL) fprintf(fp,"%s(%u)", p->mh_file, p->mh_line); 706 if (p->mh_tag != MEMTAG) 707 fprintf(fp," INVALID"); 708 nb++; 709 if (nb < 100) 710 xmlMemContentShow(fp, p); 711 else 712 fprintf(fp," skip"); 713 714 fprintf(fp,"\n"); 715 nbBytes -= (unsigned long)p->mh_size; 716 p = p->mh_next; 717 } 718 xmlMutexUnlock(xmlMemMutex); 719 #else 720 fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n"); 721 #endif 722 if (old_fp == NULL) 723 fclose(fp); 724 } 725 726 /** 727 * xmlMemDisplay: 728 * @fp: a FILE descriptor used as the output file, if NULL, the result is 729 * written to the file .memorylist 730 * 731 * show in-extenso the memory blocks allocated 732 */ 733 734 void 735 xmlMemDisplay(FILE *fp) 736 { 737 #ifdef MEM_LIST 738 MEMHDR *p; 739 unsigned idx; 740 int nb = 0; 741 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) 742 time_t currentTime; 743 char buf[500]; 744 struct tm * tstruct; 745 #endif 746 #endif 747 FILE *old_fp = fp; 748 749 if (fp == NULL) { 750 fp = fopen(".memorylist", "w"); 751 if (fp == NULL) 752 return; 753 } 754 755 #ifdef MEM_LIST 756 #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME) 757 currentTime = time(NULL); 758 tstruct = localtime(¤tTime); 759 strftime(buf, sizeof(buf) - 1, "%I:%M:%S %p", tstruct); 760 fprintf(fp," %s\n\n", buf); 761 #endif 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 * Initialize the memory layer. 939 * 940 * Returns 0 on success 941 */ 942 int 943 xmlInitMemory(void) 944 { 945 #ifdef HAVE_STDLIB_H 946 char *breakpoint; 947 #endif 948 #ifdef DEBUG_MEMORY 949 xmlGenericError(xmlGenericErrorContext, 950 "xmlInitMemory()\n"); 951 #endif 952 /* 953 This is really not good code (see Bug 130419). Suggestions for 954 improvement will be welcome! 955 */ 956 if (xmlMemInitialized) return(-1); 957 xmlMemInitialized = 1; 958 xmlMemMutex = xmlNewMutex(); 959 960 #ifdef HAVE_STDLIB_H 961 breakpoint = getenv("XML_MEM_BREAKPOINT"); 962 if (breakpoint != NULL) { 963 sscanf(breakpoint, "%ud", &xmlMemStopAtBlock); 964 } 965 #endif 966 #ifdef HAVE_STDLIB_H 967 breakpoint = getenv("XML_MEM_TRACE"); 968 if (breakpoint != NULL) { 969 sscanf(breakpoint, "%p", &xmlMemTraceBlockAt); 970 } 971 #endif 972 973 #ifdef DEBUG_MEMORY 974 xmlGenericError(xmlGenericErrorContext, 975 "xmlInitMemory() Ok\n"); 976 #endif 977 return(0); 978 } 979 980 /** 981 * xmlCleanupMemory: 982 * 983 * Free up all the memory allocated by the library for its own 984 * use. This should not be called by user level code. 985 */ 986 void 987 xmlCleanupMemory(void) { 988 #ifdef DEBUG_MEMORY 989 xmlGenericError(xmlGenericErrorContext, 990 "xmlCleanupMemory()\n"); 991 #endif 992 if (xmlMemInitialized == 0) 993 return; 994 995 xmlFreeMutex(xmlMemMutex); 996 xmlMemMutex = NULL; 997 xmlMemInitialized = 0; 998 #ifdef DEBUG_MEMORY 999 xmlGenericError(xmlGenericErrorContext, 1000 "xmlCleanupMemory() Ok\n"); 1001 #endif 1002 } 1003 1004 /** 1005 * xmlMemSetup: 1006 * @freeFunc: the free() function to use 1007 * @mallocFunc: the malloc() function to use 1008 * @reallocFunc: the realloc() function to use 1009 * @strdupFunc: the strdup() function to use 1010 * 1011 * Override the default memory access functions with a new set 1012 * This has to be called before any other libxml routines ! 1013 * 1014 * Should this be blocked if there was already some allocations 1015 * done ? 1016 * 1017 * Returns 0 on success 1018 */ 1019 int 1020 xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, 1021 xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) { 1022 #ifdef DEBUG_MEMORY 1023 xmlGenericError(xmlGenericErrorContext, 1024 "xmlMemSetup()\n"); 1025 #endif 1026 if (freeFunc == NULL) 1027 return(-1); 1028 if (mallocFunc == NULL) 1029 return(-1); 1030 if (reallocFunc == NULL) 1031 return(-1); 1032 if (strdupFunc == NULL) 1033 return(-1); 1034 xmlFree = freeFunc; 1035 xmlMalloc = mallocFunc; 1036 xmlMallocAtomic = mallocFunc; 1037 xmlRealloc = reallocFunc; 1038 xmlMemStrdup = strdupFunc; 1039 #ifdef DEBUG_MEMORY 1040 xmlGenericError(xmlGenericErrorContext, 1041 "xmlMemSetup() Ok\n"); 1042 #endif 1043 return(0); 1044 } 1045 1046 /** 1047 * xmlMemGet: 1048 * @freeFunc: place to save the free() function in use 1049 * @mallocFunc: place to save the malloc() function in use 1050 * @reallocFunc: place to save the realloc() function in use 1051 * @strdupFunc: place to save the strdup() function in use 1052 * 1053 * Provides the memory access functions set currently in use 1054 * 1055 * Returns 0 on success 1056 */ 1057 int 1058 xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, 1059 xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) { 1060 if (freeFunc != NULL) *freeFunc = xmlFree; 1061 if (mallocFunc != NULL) *mallocFunc = xmlMalloc; 1062 if (reallocFunc != NULL) *reallocFunc = xmlRealloc; 1063 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; 1064 return(0); 1065 } 1066 1067 /** 1068 * xmlGcMemSetup: 1069 * @freeFunc: the free() function to use 1070 * @mallocFunc: the malloc() function to use 1071 * @mallocAtomicFunc: the malloc() function to use for atomic allocations 1072 * @reallocFunc: the realloc() function to use 1073 * @strdupFunc: the strdup() function to use 1074 * 1075 * Override the default memory access functions with a new set 1076 * This has to be called before any other libxml routines ! 1077 * The mallocAtomicFunc is specialized for atomic block 1078 * allocations (i.e. of areas useful for garbage collected memory allocators 1079 * 1080 * Should this be blocked if there was already some allocations 1081 * done ? 1082 * 1083 * Returns 0 on success 1084 */ 1085 int 1086 xmlGcMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc, 1087 xmlMallocFunc mallocAtomicFunc, xmlReallocFunc reallocFunc, 1088 xmlStrdupFunc strdupFunc) { 1089 #ifdef DEBUG_MEMORY 1090 xmlGenericError(xmlGenericErrorContext, 1091 "xmlGcMemSetup()\n"); 1092 #endif 1093 if (freeFunc == NULL) 1094 return(-1); 1095 if (mallocFunc == NULL) 1096 return(-1); 1097 if (mallocAtomicFunc == NULL) 1098 return(-1); 1099 if (reallocFunc == NULL) 1100 return(-1); 1101 if (strdupFunc == NULL) 1102 return(-1); 1103 xmlFree = freeFunc; 1104 xmlMalloc = mallocFunc; 1105 xmlMallocAtomic = mallocAtomicFunc; 1106 xmlRealloc = reallocFunc; 1107 xmlMemStrdup = strdupFunc; 1108 #ifdef DEBUG_MEMORY 1109 xmlGenericError(xmlGenericErrorContext, 1110 "xmlGcMemSetup() Ok\n"); 1111 #endif 1112 return(0); 1113 } 1114 1115 /** 1116 * xmlGcMemGet: 1117 * @freeFunc: place to save the free() function in use 1118 * @mallocFunc: place to save the malloc() function in use 1119 * @mallocAtomicFunc: place to save the atomic malloc() function in use 1120 * @reallocFunc: place to save the realloc() function in use 1121 * @strdupFunc: place to save the strdup() function in use 1122 * 1123 * Provides the memory access functions set currently in use 1124 * The mallocAtomicFunc is specialized for atomic block 1125 * allocations (i.e. of areas useful for garbage collected memory allocators 1126 * 1127 * Returns 0 on success 1128 */ 1129 int 1130 xmlGcMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc, 1131 xmlMallocFunc *mallocAtomicFunc, xmlReallocFunc *reallocFunc, 1132 xmlStrdupFunc *strdupFunc) { 1133 if (freeFunc != NULL) *freeFunc = xmlFree; 1134 if (mallocFunc != NULL) *mallocFunc = xmlMalloc; 1135 if (mallocAtomicFunc != NULL) *mallocAtomicFunc = xmlMallocAtomic; 1136 if (reallocFunc != NULL) *reallocFunc = xmlRealloc; 1137 if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup; 1138 return(0); 1139 } 1140 1141 #define bottom_xmlmemory 1142 #include "elfgcchack.h" 1143