Annotation of XML/xmlmemory.c, revision 1.11

1.1       daniel      1: /*
                      2:  * memory.c:  libxml memory allocator wrapper.
                      3:  *
                      4:  * Daniel.Veillard@w3.org
                      5:  */
                      6: 
1.3       daniel      7: #ifdef WIN32
1.9       daniel      8: #include "win32config.h"
1.3       daniel      9: #else
1.4       daniel     10: #include "config.h"
1.3       daniel     11: #endif
                     12: 
                     13: #include <stdio.h>
                     14: #include <string.h>
                     15: 
                     16: #ifdef HAVE_SYS_TYPES_H
1.1       daniel     17: #include <sys/types.h>
1.3       daniel     18: #endif
1.4       daniel     19: #ifdef HAVE_TIME_H
                     20: #include <time.h>
                     21: #endif
1.3       daniel     22: #ifdef HAVE_MALLOC_H
1.1       daniel     23: #include <malloc.h>
1.3       daniel     24: #endif
1.7       daniel     25: #ifdef HAVE_STDLIB_H
                     26: #include <stdlib.h>
                     27: #endif
1.11    ! daniel     28: #ifdef HAVE_CTYPE_H
        !            29: #include <ctype.h>
        !            30: #endif
1.7       daniel     31: 
1.3       daniel     32: 
1.1       daniel     33: #include "xmlmemory.h"
                     34: 
1.2       daniel     35: #ifndef NO_DEBUG_MEMORY
1.1       daniel     36: #ifdef xmlMalloc
                     37: #undef xmlMalloc
                     38: #endif
                     39: #ifdef xmlRealloc
                     40: #undef xmlRealloc
                     41: #endif
                     42: #ifdef xmlMemStrdup
                     43: #undef xmlMemStrdup
                     44: #endif
1.6       daniel     45: 
1.1       daniel     46: extern void xmlMemoryDump(void);
                     47: 
                     48: /*
                     49:  * Each of the blocks allocated begin with a header containing informations
                     50:  */
                     51: 
                     52: #define MEMTAG 0x5aa5
                     53: 
                     54: #define MALLOC_TYPE 1
                     55: #define REALLOC_TYPE 2
                     56: #define STRDUP_TYPE 3
                     57: 
                     58: typedef struct memnod {
                     59:     unsigned int   mh_tag;
                     60:     unsigned int   mh_type;
                     61:     unsigned long  mh_number;
                     62:     size_t         mh_size;
                     63: #ifdef MEM_LIST
                     64:    struct memnod *mh_next;
                     65:    struct memnod *mh_prev;
                     66: #endif
                     67:    const char    *mh_file;
                     68:    unsigned int   mh_line;
                     69: }  MEMHDR;
                     70: 
                     71: 
                     72: #ifdef SUN4
                     73: #define ALIGN_SIZE  16
                     74: #else
                     75: #define ALIGN_SIZE  sizeof(double)
                     76: #endif
                     77: #define HDR_SIZE    sizeof(MEMHDR)
                     78: #define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
                     79:                      / ALIGN_SIZE ) * ALIGN_SIZE)
                     80: 
                     81: 
                     82: #define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
                     83: #define HDR_2_CLIENT(a)    ((void *) (((char *) (a)) + RESERVE_SIZE))
                     84: 
                     85: 
                     86: static unsigned long  debugMemSize = 0;
1.7       daniel     87: static unsigned long  debugMaxMemSize = 0;
1.1       daniel     88: static int block=0;
1.7       daniel     89: int xmlMemStopAtBlock = 0;
                     90: int xmlMemInitialized = 0;
1.1       daniel     91: #ifdef MEM_LIST
                     92: static MEMHDR *memlist = NULL;
                     93: #endif
                     94: 
                     95: void debugmem_tag_error(void *addr);
                     96: #ifdef MEM_LIST
                     97: void  debugmem_list_add(MEMHDR *);
                     98: void debugmem_list_delete(MEMHDR *);
                     99: #endif
                    100: #define Mem_Tag_Err(a) debugmem_tag_error(a);
                    101: 
                    102: #ifndef TEST_POINT
                    103: #define TEST_POINT
                    104: #endif
                    105: 
                    106: /**
1.7       daniel    107:  * xmlMallocBreakpoint:
                    108:  *
                    109:  * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
                    110:  * number reaches the specified value this function is called. One need to add a breakpoint
                    111:  * to it to get the context in which the given block is allocated.
                    112:  */
                    113: 
                    114: void
                    115: xmlMallocBreakpoint(void) {
                    116:     fprintf(stderr, "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
                    117: }
                    118: 
                    119: /**
1.1       daniel    120:  * xmlMallocLoc:
                    121:  * @size:  an int specifying the size in byte to allocate.
                    122:  * @file:  the file name or NULL
1.7       daniel    123:   @file:  the line number
1.1       daniel    124:  *
                    125:  * a malloc() equivalent, with logging of the allocation info.
                    126:  *
                    127:  * Returns a pointer to the allocated area or NULL in case of lack of memory.
                    128:  */
                    129: 
                    130: void *
                    131: xmlMallocLoc(int size, const char * file, int line)
                    132: {
                    133:     MEMHDR *p;
                    134:     
1.7       daniel    135:     if (!xmlMemInitialized) xmlInitMemory();
1.1       daniel    136: #ifdef DEBUG_MEMORY
                    137:     fprintf(stderr, "Malloc(%d)\n",size);
                    138: #endif
                    139: 
                    140:     TEST_POINT
                    141:     
                    142:     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
                    143: 
                    144:     if (!p) {
1.8       daniel    145:        fprintf(stderr, "xmlMalloc : Out of free space\n");
                    146:        xmlMemoryDump();
                    147:        return(NULL);
1.1       daniel    148:     }   
                    149:     p->mh_tag = MEMTAG;
                    150:     p->mh_number = ++block;
                    151:     p->mh_size = size;
                    152:     p->mh_type = MALLOC_TYPE;
                    153:     p->mh_file = file;
                    154:     p->mh_line = line;
                    155:     debugMemSize += size;
1.7       daniel    156:     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
1.1       daniel    157: #ifdef MEM_LIST
                    158:     debugmem_list_add(p);
                    159: #endif
                    160: 
                    161: #ifdef DEBUG_MEMORY
                    162:     fprintf(stderr, "Malloc(%d) Ok\n",size);
                    163: #endif
                    164:     
1.7       daniel    165:     if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
1.1       daniel    166: 
                    167:     TEST_POINT
                    168: 
                    169:     return(HDR_2_CLIENT(p));
                    170: }
                    171: 
                    172: /**
                    173:  * xmlMalloc:
                    174:  * @size:  an int specifying the size in byte to allocate.
                    175:  *
                    176:  * a malloc() equivalent, with logging of the allocation info.
                    177:  *
                    178:  * Returns a pointer to the allocated area or NULL in case of lack of memory.
                    179:  */
                    180: 
                    181: void *
                    182: xmlMalloc(int size)
                    183: {
                    184:     return(xmlMallocLoc(size, "none", 0));
                    185: }
                    186: 
                    187: /**
                    188:  * xmlReallocLoc:
                    189:  * @ptr:  the initial memory block pointer
                    190:  * @size:  an int specifying the size in byte to allocate.
                    191:  * @file:  the file name or NULL
                    192:  * @file:  the line number
                    193:  *
                    194:  * a realloc() equivalent, with logging of the allocation info.
                    195:  *
                    196:  * Returns a pointer to the allocated area or NULL in case of lack of memory.
                    197:  */
                    198: 
                    199: void *
                    200: xmlReallocLoc(void *ptr,int size, const char * file, int line)
                    201: {
                    202:     MEMHDR *p;
                    203:     unsigned long number;
                    204: 
1.7       daniel    205:     if (!xmlMemInitialized) xmlInitMemory();
1.1       daniel    206:     TEST_POINT
                    207: 
                    208:     p = CLIENT_2_HDR(ptr);
                    209:     number = p->mh_number;
                    210:     if (p->mh_tag != MEMTAG) {
1.4       daniel    211:        Mem_Tag_Err(p);
1.1       daniel    212:         goto error;
                    213:     }
                    214:     p->mh_tag = ~MEMTAG;
                    215:     debugMemSize -= p->mh_size;
                    216: #ifdef MEM_LIST
                    217:     debugmem_list_delete(p);
                    218: #endif
                    219: 
                    220:     p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
                    221:     if (!p) {
                    222:         goto error;
                    223:     }
                    224:     p->mh_tag = MEMTAG;
                    225:     p->mh_number = number;
                    226:     p->mh_type = REALLOC_TYPE;
                    227:     p->mh_size = size;
                    228:     p->mh_file = file;
                    229:     p->mh_line = line;
                    230:     debugMemSize += size;
1.7       daniel    231:     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
1.1       daniel    232: #ifdef MEM_LIST
                    233:     debugmem_list_add(p);
                    234: #endif
                    235: 
                    236:     TEST_POINT
                    237: 
                    238:     return(HDR_2_CLIENT(p));
                    239:     
                    240: error:    
                    241:     return(NULL);
                    242: }
                    243: 
                    244: /**
                    245:  * xmlRealloc:
                    246:  * @ptr:  the initial memory block pointer
                    247:  * @size:  an int specifying the size in byte to allocate.
                    248:  *
                    249:  * a realloc() equivalent, with logging of the allocation info.
                    250:  *
                    251:  * Returns a pointer to the allocated area or NULL in case of lack of memory.
                    252:  */
                    253: 
                    254: void *
                    255: xmlRealloc(void *ptr,int size) {
                    256:     return(xmlReallocLoc(ptr, size, "none", 0));
                    257: }
                    258: 
                    259: /**
                    260:  * xmlFree:
                    261:  * @ptr:  the memory block pointer
                    262:  *
                    263:  * a free() equivalent, with error checking.
                    264:  */
                    265: void
                    266: xmlFree(void *ptr)
                    267: {
                    268:     MEMHDR *p;
                    269: 
                    270:     TEST_POINT
                    271: 
                    272:     p = CLIENT_2_HDR(ptr);
                    273:     if (p->mh_tag != MEMTAG) {
1.4       daniel    274:        Mem_Tag_Err(p);
                    275:        goto error;
1.1       daniel    276:     }
                    277:     p->mh_tag = ~MEMTAG;
                    278:     debugMemSize -= p->mh_size;
                    279: 
                    280: #ifdef MEM_LIST
                    281:     debugmem_list_delete(p);
                    282: #endif
                    283:     free(p);
                    284: 
                    285:     TEST_POINT
                    286: 
                    287:     return;
                    288:     
                    289: error:    
                    290:     fprintf(stderr, "xmlFree(%X) error\n", (unsigned int) ptr);
                    291:     return;
                    292: }
                    293: 
                    294: /**
                    295:  * xmlMemStrdupLoc:
                    296:  * @ptr:  the initial string pointer
                    297:  * @file:  the file name or NULL
                    298:  * @file:  the line number
                    299:  *
                    300:  * a strdup() equivalent, with logging of the allocation info.
                    301:  *
                    302:  * Returns a pointer to the new string or NULL if allocation error occured.
                    303:  */
                    304: 
                    305: char *
                    306: xmlMemStrdupLoc(const char *str, const char *file, int line)
                    307: {
                    308:     char *s;
                    309:     size_t size = strlen(str) + 1;
                    310:     MEMHDR *p;
                    311: 
1.7       daniel    312:     if (!xmlMemInitialized) xmlInitMemory();
1.1       daniel    313:     TEST_POINT
                    314: 
                    315:     p = (MEMHDR *) malloc(RESERVE_SIZE+size);
                    316:     if (!p) {
1.4       daniel    317:       goto error;
1.1       daniel    318:     }
                    319:     p->mh_tag = MEMTAG;
                    320:     p->mh_number = ++block;
                    321:     p->mh_size = size;
                    322:     p->mh_type = STRDUP_TYPE;
                    323:     p->mh_file = file;
                    324:     p->mh_line = line;
                    325:     debugMemSize += size;
1.7       daniel    326:     if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
1.1       daniel    327: #ifdef MEM_LIST
                    328:     debugmem_list_add(p);
                    329: #endif
                    330:     s = HDR_2_CLIENT(p);
                    331:     
1.7       daniel    332:     if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
                    333: 
1.1       daniel    334:     if (s != NULL)
1.4       daniel    335:       strcpy(s,str);
1.1       daniel    336:     else
1.4       daniel    337:       goto error;
1.1       daniel    338:     
                    339:     TEST_POINT
                    340: 
                    341:     return(s);
                    342: 
                    343: error:
                    344:     return(NULL);
                    345: }
                    346: 
                    347: /**
                    348:  * xmlMemStrdup:
                    349:  * @ptr:  the initial string pointer
                    350:  *
                    351:  * a strdup() equivalent, with logging of the allocation info.
                    352:  *
                    353:  * Returns a pointer to the new string or NULL if allocation error occured.
                    354:  */
                    355: 
                    356: char *
                    357: xmlMemStrdup(const char *str) {
                    358:     return(xmlMemStrdupLoc(str, "none", 0));
                    359: }
                    360: 
                    361: /**
                    362:  * xmlMemUsed:
                    363:  *
                    364:  * returns the amount of memory currenly allocated
                    365:  *
                    366:  * Returns an int representing the amount of memory allocated.
                    367:  */
                    368: 
                    369: int
                    370: xmlMemUsed(void) {
                    371:      return(debugMemSize);
                    372: }
                    373: 
1.11    ! daniel    374: #ifdef MEM_LIST
        !           375: /**
        !           376:  * xmlMemContentShow:
        !           377:  * @fp:  a FILE descriptor used as the output file
        !           378:  * @p:  a memory block header
        !           379:  *
        !           380:  * tries to show some content from the memory block
        !           381:  */
        !           382: 
        !           383: void
        !           384: xmlMemContentShow(FILE *fp, MEMHDR *p)
        !           385: {
        !           386:     int i,j,len = p->mh_size;
        !           387:     const char *buf = HDR_2_CLIENT(p);
        !           388: 
        !           389:     for (i = 0;i < len;i++) {
        !           390:         if (buf[i] == 0) break;
        !           391:        if (!isprint(buf[i])) break;
        !           392:     }
        !           393:     if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
        !           394:         if (len >= 4) {
        !           395:            MEMHDR *q;
        !           396:            void *cur;
        !           397: 
        !           398:             for (j = 0;j < len -3;j += 4) {
        !           399:                cur = *((void **) &buf[j]);
        !           400:                q = CLIENT_2_HDR(cur);
        !           401:                p = memlist;
        !           402:                while (p != NULL) {
        !           403:                    if (p == q) break;
        !           404:                    p = p->mh_next;
        !           405:                }
        !           406:                if (p == q) {
        !           407:                    fprintf(fp, " pointer to #%lu at index %d",
        !           408:                            p->mh_number, j);
        !           409:                    return;
        !           410:                }
        !           411:            }
        !           412:        }
        !           413:     } else if ((i == 0) && (buf[i] == 0)) {
        !           414:         fprintf(fp," null");
        !           415:     } else {
        !           416:         if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); 
        !           417:        else {
        !           418:             fprintf(fp," [");
        !           419:            for (j = 0;j < i;j++)
        !           420:                 fprintf(fp,"%c", buf[j]);
        !           421:             fprintf(fp,"]");
        !           422:        }
        !           423:     }
        !           424: }
        !           425: #endif
        !           426: 
1.1       daniel    427: /**
1.10      daniel    428:  * xmlMemShow:
                    429:  * @fp:  a FILE descriptor used as the output file
                    430:  * @nr:  number of entries to dump
                    431:  *
                    432:  * show a show display of the memory allocated, and dump
                    433:  * the @nr last allocated areas which were not freed
                    434:  */
                    435: 
                    436: void
                    437: xmlMemShow(FILE *fp, int nr)
                    438: {
                    439: #ifdef MEM_LIST
                    440:     MEMHDR *p;
                    441: #endif
                    442: 
                    443:     if (fp != NULL)
                    444:        fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
                    445:                debugMemSize, debugMaxMemSize);
                    446: #ifdef MEM_LIST
                    447:     if (nr > 0) {
                    448:        fprintf(fp,"NUMBER   SIZE  TYPE   WHERE\n");
                    449:        p = memlist;
                    450:        while ((p) && nr > 0) {
                    451:              fprintf(fp,"%6lu %6u ",p->mh_number,p->mh_size);
                    452:            switch (p->mh_type) {
                    453:               case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
                    454:               case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
                    455:              case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
                    456:                        default:fprintf(fp,"   ???    in ");break;
                    457:            }
                    458:            if (p->mh_file != NULL)
                    459:                fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
                    460:            if (p->mh_tag != MEMTAG)
                    461:                fprintf(fp,"  INVALID");
1.11    ! daniel    462:            xmlMemContentShow(fp, p);
1.10      daniel    463:            fprintf(fp,"\n");
                    464:            nr--;
                    465:            p = p->mh_next;
                    466:        }
                    467:     }
                    468: #endif /* MEM_LIST */    
                    469: }
                    470: 
                    471: /**
1.1       daniel    472:  * xmlMemDisplay:
                    473:  * @fp:  a FILE descriptor used as the output file, if NULL, the result is
1.10      daniel    474:  *       written to the file .memorylist
1.1       daniel    475:  *
                    476:  * show in-extenso the memory blocks allocated
                    477:  */
                    478: 
                    479: void
                    480: xmlMemDisplay(FILE *fp)
                    481: {
                    482: #ifdef MEM_LIST
1.4       daniel    483:     MEMHDR *p;
                    484:     int     idx;
                    485: #if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
1.5       daniel    486:     time_t currentTime;
1.4       daniel    487:     char buf[500];
                    488:     struct tm * tstruct;
                    489: 
1.5       daniel    490:     currentTime = time(NULL);
                    491:     tstruct = localtime(&currentTime);
1.4       daniel    492:     strftime(buf, sizeof(buf) - 1, "%c", tstruct);
                    493:     fprintf(fp,"      %s\n\n", buf);
                    494: #endif
                    495: 
1.1       daniel    496:     
1.7       daniel    497:     fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
                    498:             debugMemSize, debugMaxMemSize);
1.4       daniel    499:     fprintf(fp,"BLOCK  NUMBER   SIZE  TYPE\n");
                    500:     idx = 0;
                    501:     p = memlist;
                    502:     while (p) {
1.1       daniel    503:          fprintf(fp,"%-5u  %6lu %6u ",idx++,p->mh_number,p->mh_size);
1.4       daniel    504:         switch (p->mh_type) {
                    505:            case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
                    506:            case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
                    507:           case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
                    508:                     default:fprintf(fp,"   ???    in ");break;
                    509:         }
1.1       daniel    510:          if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
1.4       daniel    511:         if (p->mh_tag != MEMTAG)
1.1       daniel    512:              fprintf(fp,"  INVALID");
1.11    ! daniel    513:        xmlMemContentShow(fp, p);
1.4       daniel    514:         fprintf(fp,"\n");
                    515:         p = p->mh_next;
                    516:     }
1.1       daniel    517: #else
1.4       daniel    518:     fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
1.1       daniel    519: #endif
                    520: }
                    521: 
                    522: #ifdef MEM_LIST
                    523: 
                    524: void debugmem_list_add(MEMHDR *p)
                    525: {
1.4       daniel    526:      p->mh_next = memlist;
                    527:      p->mh_prev = NULL;
                    528:      if (memlist) memlist->mh_prev = p;
                    529:      memlist = p;
1.1       daniel    530: #ifdef MEM_LIST_DEBUG
1.4       daniel    531:      if (stderr)
                    532:      Mem_Display(stderr);
1.1       daniel    533: #endif
                    534: }
                    535: 
                    536: void debugmem_list_delete(MEMHDR *p)
                    537: {
1.4       daniel    538:      if (p->mh_next)
                    539:      p->mh_next->mh_prev = p->mh_prev;
                    540:      if (p->mh_prev)
                    541:      p->mh_prev->mh_next = p->mh_next;
                    542:      else memlist = p->mh_next;
1.1       daniel    543: #ifdef MEM_LIST_DEBUG
1.4       daniel    544:      if (stderr)
                    545:      Mem_Display(stderr);
1.1       daniel    546: #endif
                    547: }
                    548: 
                    549: #endif
                    550: 
                    551: /*
                    552:  * debugmem_tag_error : internal error function.
                    553:  */
                    554:  
                    555: void debugmem_tag_error(void *p)
                    556: {
1.4       daniel    557:      fprintf(stderr, "Memory tag error occurs :%p \n\t bye\n", p);
1.1       daniel    558: #ifdef MEM_LIST
1.4       daniel    559:      if (stderr)
                    560:      xmlMemDisplay(stderr);
1.1       daniel    561: #endif
                    562: }
                    563: 
                    564: FILE *xmlMemoryDumpFile = NULL;
                    565: 
                    566: 
                    567: /**
                    568:  * xmlMemoryDump:
                    569:  *
                    570:  * Dump in-extenso the memory blocks allocated to the file .memorylist
                    571:  */
                    572: 
                    573: void
                    574: xmlMemoryDump(void)
                    575: {
                    576:     FILE *dump;
                    577: 
                    578:     dump = fopen(".memdump", "w");
                    579:     if (dump == NULL) xmlMemoryDumpFile = stdout;
                    580:     else xmlMemoryDumpFile = dump;
                    581: 
                    582:     xmlMemDisplay(xmlMemoryDumpFile);
                    583: 
                    584:     if (dump != NULL) fclose(dump);
                    585: }
                    586: 
                    587: 
                    588: /****************************************************************
                    589:  *                                                             *
                    590:  *             Initialization Routines                         *
                    591:  *                                                             *
                    592:  ****************************************************************/
                    593: 
                    594: /**
                    595:  * xmlInitMemory:
                    596:  *
                    597:  * Initialize the memory layer.
1.6       daniel    598:  *
                    599:  * Returns 0 on success
1.1       daniel    600:  */
                    601: 
                    602: 
                    603: int
                    604: xmlInitMemory(void)
                    605: {
                    606:      int ret;
1.7       daniel    607:      
                    608: #ifdef HAVE_STDLIB_H
                    609:      char *breakpoint;
                    610: 
                    611:      breakpoint = getenv("XML_MEM_BREAKPOINT");
                    612:      if (breakpoint != NULL) {
                    613:          sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
                    614:      }
                    615: #endif     
1.1       daniel    616:     
                    617: #ifdef DEBUG_MEMORY
                    618:      fprintf(stderr, "xmlInitMemory() Ok\n");
                    619: #endif     
                    620:      ret = 0;
                    621:      return(ret);
                    622: }
                    623: 
1.2       daniel    624: #endif /* ! NO_DEBUG_MEMORY */

Webmaster