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