Annotation of embedaddon/libxml2/xmlmemory.c, revision 1.1
1.1 ! misho 1: /*
! 2: * xmlmemory.c: libxml memory allocator wrapper.
! 3: *
! 4: * daniel@veillard.com
! 5: */
! 6:
! 7: #define IN_LIBXML
! 8: #include "libxml.h"
! 9:
! 10: #include <string.h>
! 11:
! 12: #ifdef HAVE_SYS_TYPES_H
! 13: #include <sys/types.h>
! 14: #endif
! 15:
! 16: #ifdef HAVE_TIME_H
! 17: #include <time.h>
! 18: #endif
! 19:
! 20: #ifdef HAVE_STDLIB_H
! 21: #include <stdlib.h>
! 22: #else
! 23: #ifdef HAVE_MALLOC_H
! 24: #include <malloc.h>
! 25: #endif
! 26: #endif
! 27:
! 28: #ifdef HAVE_CTYPE_H
! 29: #include <ctype.h>
! 30: #endif
! 31:
! 32: /* #define DEBUG_MEMORY */
! 33:
! 34: /**
! 35: * MEM_LIST:
! 36: *
! 37: * keep track of all allocated blocks for error reporting
! 38: * Always build the memory list !
! 39: */
! 40: #ifdef DEBUG_MEMORY_LOCATION
! 41: #ifndef MEM_LIST
! 42: #define MEM_LIST /* keep a list of all the allocated memory blocks */
! 43: #endif
! 44: #endif
! 45:
! 46: #include <libxml/globals.h> /* must come before xmlmemory.h */
! 47: #include <libxml/xmlmemory.h>
! 48: #include <libxml/xmlerror.h>
! 49: #include <libxml/threads.h>
! 50:
! 51: static int xmlMemInitialized = 0;
! 52: static unsigned long debugMemSize = 0;
! 53: static unsigned long debugMemBlocks = 0;
! 54: static unsigned long debugMaxMemSize = 0;
! 55: static xmlMutexPtr xmlMemMutex = NULL;
! 56:
! 57: void xmlMallocBreakpoint(void);
! 58:
! 59: /************************************************************************
! 60: * *
! 61: * Macros, variables and associated types *
! 62: * *
! 63: ************************************************************************/
! 64:
! 65: #if !defined(LIBXML_THREAD_ENABLED) && !defined(LIBXML_THREAD_ALLOC_ENABLED)
! 66: #ifdef xmlMalloc
! 67: #undef xmlMalloc
! 68: #endif
! 69: #ifdef xmlRealloc
! 70: #undef xmlRealloc
! 71: #endif
! 72: #ifdef xmlMemStrdup
! 73: #undef xmlMemStrdup
! 74: #endif
! 75: #endif
! 76:
! 77: /*
! 78: * Each of the blocks allocated begin with a header containing informations
! 79: */
! 80:
! 81: #define MEMTAG 0x5aa5
! 82:
! 83: #define MALLOC_TYPE 1
! 84: #define REALLOC_TYPE 2
! 85: #define STRDUP_TYPE 3
! 86: #define MALLOC_ATOMIC_TYPE 4
! 87: #define REALLOC_ATOMIC_TYPE 5
! 88:
! 89: typedef struct memnod {
! 90: unsigned int mh_tag;
! 91: unsigned int mh_type;
! 92: unsigned long mh_number;
! 93: size_t mh_size;
! 94: #ifdef MEM_LIST
! 95: struct memnod *mh_next;
! 96: struct memnod *mh_prev;
! 97: #endif
! 98: const char *mh_file;
! 99: unsigned int mh_line;
! 100: } MEMHDR;
! 101:
! 102:
! 103: #ifdef SUN4
! 104: #define ALIGN_SIZE 16
! 105: #else
! 106: #define ALIGN_SIZE sizeof(double)
! 107: #endif
! 108: #define HDR_SIZE sizeof(MEMHDR)
! 109: #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
! 110: / ALIGN_SIZE ) * ALIGN_SIZE)
! 111:
! 112:
! 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"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>