Annotation of XML/xmlmemory.c, revision 1.5

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

Webmaster