Annotation of XML/xmlmemory.c, revision 1.7

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

Webmaster