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