File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / xmlmemory.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:29 2014 UTC (10 years ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

    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(%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(&currentTime);
  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"

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>