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