Annotation of micropolis/src/tcl/tclckall.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * tclCkalloc.c --
                      3:  *    Interface to malloc and free that provides support for debugging problems
                      4:  *    involving overwritten, double freeing memory and loss of memory.
                      5:  *
                      6:  * Copyright 1991 Regents of the University of California
                      7:  * Permission to use, copy, modify, and distribute this
                      8:  * software and its documentation for any purpose and without
                      9:  * fee is hereby granted, provided that the above copyright
                     10:  * notice appear in all copies.  The University of California
                     11:  * makes no representations about the suitability of this
                     12:  * software for any purpose.  It is provided "as is" without
                     13:  * express or implied warranty.
                     14:  *
                     15:  * This code contributed by Karl Lehenbauer and Mark Diekhans
                     16:  *
                     17:  */
                     18: 
                     19: #include "tclint.h"
                     20: 
                     21: #define FALSE  0
                     22: #define TRUE   1
                     23: 
                     24: #ifdef TCL_MEM_DEBUG
                     25: #ifndef TCL_GENERIC_ONLY
                     26: #include "tclunix.h"
                     27: #endif
                     28: 
                     29: #define GUARD_SIZE 8
                     30: 
                     31: struct mem_header {
                     32:         long               length;
                     33:         char              *file;
                     34:         int                line;
                     35:         struct mem_header *flink;
                     36:         struct mem_header *blink;
                     37:         unsigned char      low_guard[GUARD_SIZE];
                     38:         char               body[1];
                     39: };
                     40: 
                     41: static struct mem_header *allocHead = NULL;  /* List of allocated structures */
                     42: 
                     43: #define GUARD_VALUE  0341
                     44: 
                     45: /* static char high_guard[] = {0x89, 0xab, 0xcd, 0xef}; */
                     46: 
                     47: static int total_mallocs = 0;
                     48: static int total_frees = 0;
                     49: static int current_bytes_malloced = 0;
                     50: static int maximum_bytes_malloced = 0;
                     51: static int current_malloc_packets = 0;
                     52: static int maximum_malloc_packets = 0;
                     53: static int break_on_malloc = 0;
                     54: static int trace_on_at_malloc = 0;
                     55: static int  alloc_tracing = FALSE;
                     56: static int  init_malloced_bodies = FALSE;
                     57: #ifdef MEM_VALIDATE
                     58:     static int  validate_memory = TRUE;
                     59: #else
                     60:     static int  validate_memory = FALSE;
                     61: #endif
                     62: 
                     63: 
                     64: /*
                     65:  *----------------------------------------------------------------------
                     66:  *
                     67:  * dump_memory_info --
                     68:  *     Display the global memory management statistics.
                     69:  *
                     70:  *----------------------------------------------------------------------
                     71:  */
                     72: static void
                     73: dump_memory_info(outFile) 
                     74:     FILE *outFile;
                     75: {
                     76:         fprintf(outFile,"total mallocs             %10d\n", 
                     77:                 total_mallocs);
                     78:         fprintf(outFile,"total frees               %10d\n", 
                     79:                 total_frees);
                     80:         fprintf(outFile,"current packets allocated %10d\n", 
                     81:                 current_malloc_packets);
                     82:         fprintf(outFile,"current bytes allocated   %10d\n", 
                     83:                 current_bytes_malloced);
                     84:         fprintf(outFile,"maximum packets allocated %10d\n", 
                     85:                 maximum_malloc_packets);
                     86:         fprintf(outFile,"maximum bytes allocated   %10d\n", 
                     87:                 maximum_bytes_malloced);
                     88: }
                     89: 
                     90: /*
                     91:  *----------------------------------------------------------------------
                     92:  *
                     93:  * ValidateMemory --
                     94:  *     Procedure to validate allocted memory guard zones.
                     95:  *
                     96:  *----------------------------------------------------------------------
                     97:  */
                     98: static void
                     99: ValidateMemory (memHeaderP, file, line, nukeGuards)
                    100:     struct mem_header *memHeaderP;
                    101:     char              *file;
                    102:     int                line;
                    103:     int                nukeGuards;
                    104: {
                    105:     unsigned char *hiPtr;
                    106:     int   idx;
                    107:     int   guard_failed = FALSE;
                    108: 
                    109:     for (idx = 0; idx < GUARD_SIZE; idx++)
                    110:         if (*(memHeaderP->low_guard + idx) != GUARD_VALUE) {
                    111:             guard_failed = TRUE;
                    112:             fflush (stdout);
                    113:             fprintf(stderr, "low guard byte %d is 0x%x\n", idx, 
                    114:                     *(memHeaderP->low_guard + idx) & 0xff);
                    115:         }
                    116: 
                    117:     if (guard_failed) {
                    118:         dump_memory_info (stderr);
                    119:         fprintf (stderr, "low guard failed at %lx, %s %d\n",
                    120:                  memHeaderP->body, file, line);
                    121:         fflush (stderr);  /* In case name pointer is bad. */
                    122:         fprintf (stderr, "Allocated at (%s %d)\n", memHeaderP->file,
                    123:                  memHeaderP->line);
                    124:         panic ("Memory validation failure");
                    125:     }
                    126: 
                    127:     hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length;
                    128:     for (idx = 0; idx < GUARD_SIZE; idx++)
                    129:         if (*(hiPtr + idx) != GUARD_VALUE) {
                    130:             guard_failed = TRUE;
                    131:             fflush (stdout);
                    132:             fprintf(stderr, "hi guard byte %d is 0x%x\n", idx, 
                    133:                     *(hiPtr+idx) & 0xff);
                    134:         }
                    135: 
                    136:     if (guard_failed) {
                    137:         dump_memory_info (stderr);
                    138:         fprintf (stderr, "high guard failed at %lx, %s %d\n",
                    139:                  memHeaderP->body, file, line);
                    140:         fflush (stderr);  /* In case name pointer is bad. */
                    141:         fprintf (stderr, "Allocated at (%s %d)\n", memHeaderP->file,
                    142:                  memHeaderP->line);
                    143:         panic ("Memory validation failure");
                    144:     }
                    145: 
                    146:     if (nukeGuards) {
                    147:         memset ((char *) memHeaderP->low_guard, 0, GUARD_SIZE); 
                    148:         memset ((char *) hiPtr, 0, GUARD_SIZE); 
                    149:     }
                    150: 
                    151: }
                    152: 
                    153: /*
                    154:  *----------------------------------------------------------------------
                    155:  *
                    156:  * Tcl_ValidateAllMemory --
                    157:  *     Validates guard regions for all allocated memory.
                    158:  *
                    159:  *----------------------------------------------------------------------
                    160:  */
                    161: void
                    162: Tcl_ValidateAllMemory (file, line)
                    163:     char  *file;
                    164:     int    line;
                    165: {
                    166:     struct mem_header *memScanP;
                    167: 
                    168:     for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink)
                    169:         ValidateMemory (memScanP, file, line, FALSE);
                    170: 
                    171: }
                    172: 
                    173: /*
                    174:  *----------------------------------------------------------------------
                    175:  *
                    176:  * Tcl_DumpActiveMemory --
                    177:  *     Displays all allocated memory to stderr.
                    178:  *
                    179:  * Results:
                    180:  *     Return TCL_ERROR if an error accessing the file occures, `errno' 
                    181:  *     will have the file error number left in it.
                    182:  *----------------------------------------------------------------------
                    183:  */
                    184: int
                    185: Tcl_DumpActiveMemory (fileName)
                    186:     char *fileName;
                    187: {
                    188:     FILE              *fileP;
                    189:     struct mem_header *memScanP;
                    190:     char              *address;
                    191: 
                    192: #ifdef MSDOS
                    193:     fileP = fopen (fileName, "wb");
                    194: #else
                    195:     fileP = fopen (fileName, "w");
                    196: #endif
                    197:     if (fileP == NULL)
                    198:         return TCL_ERROR;
                    199: 
                    200:     for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) {
                    201:         address = &memScanP->body [0];
                    202:         fprintf (fileP, "%8lx - %8lx  %7d @ %s %d\n", address,
                    203:                  address + memScanP->length - 1, memScanP->length,
                    204:                  memScanP->file, memScanP->line);
                    205:     }
                    206:     fclose (fileP);
                    207:     return TCL_OK;
                    208: }
                    209: 
                    210: /*
                    211:  *----------------------------------------------------------------------
                    212:  *
                    213:  * Tcl_DbCkalloc - debugging ckalloc
                    214:  *
                    215:  *        Allocate the requested amount of space plus some extra for
                    216:  *        guard bands at both ends of the request, plus a size, panicing 
                    217:  *        if there isn't enough space, then write in the guard bands
                    218:  *        and return the address of the space in the middle that the
                    219:  *        user asked for.
                    220:  *
                    221:  *        The second and third arguments are file and line, these contain
                    222:  *        the filename and line number corresponding to the caller.
                    223:  *        These are sent by the ckalloc macro; it uses the preprocessor
                    224:  *        autodefines __FILE__ and __LINE__.
                    225:  *
                    226:  *----------------------------------------------------------------------
                    227:  */
                    228: char *
                    229: Tcl_DbCkalloc(size, file, line)
                    230:     unsigned int size;
                    231:     char        *file;
                    232:     int          line;
                    233: {
                    234:     struct mem_header *result;
                    235: 
                    236:     if (validate_memory)
                    237:         Tcl_ValidateAllMemory (file, line);
                    238: 
                    239:     result = (struct mem_header *)malloc((unsigned)size + 
                    240:                               sizeof(struct mem_header) + GUARD_SIZE);
                    241:     if (result == NULL) {
                    242:         fflush(stdout);
                    243:         dump_memory_info(stderr);
                    244:         panic("unable to alloc %d bytes, %s line %d", size, file, 
                    245:               line);
                    246:     }
                    247: 
                    248:     /*
                    249:      * Fill in guard zones and size.  Link into allocated list.
                    250:      */
                    251:     result->length = size;
                    252:     result->file = file;
                    253:     result->line = line;
                    254:     memset ((char *) result->low_guard, GUARD_VALUE, GUARD_SIZE);
                    255:     memset (result->body + size, GUARD_VALUE, GUARD_SIZE);
                    256:     result->flink = allocHead;
                    257:     result->blink = NULL;
                    258:     if (allocHead != NULL)
                    259:         allocHead->blink = result;
                    260:     allocHead = result;
                    261: 
                    262:     total_mallocs++;
                    263:     if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) {
                    264:         (void) fflush(stdout);
                    265:         fprintf(stderr, "reached malloc trace enable point (%d)\n",
                    266:                 total_mallocs);
                    267:         fflush(stderr);
                    268:         alloc_tracing = TRUE;
                    269:         trace_on_at_malloc = 0;
                    270:     }
                    271: 
                    272:     if (alloc_tracing)
                    273:         fprintf(stderr,"ckalloc %lx %d %s %d\n", result->body, size, 
                    274:                 file, line);
                    275: 
                    276:     if (break_on_malloc && (total_mallocs >= break_on_malloc)) {
                    277:         break_on_malloc = 0;
                    278:         (void) fflush(stdout);
                    279:         fprintf(stderr,"reached malloc break limit (%d)\n", 
                    280:                 total_mallocs);
                    281:         fprintf(stderr, "program will now enter C debugger\n");
                    282:         (void) fflush(stderr);
                    283:         kill (getpid(), SIGINT);
                    284:     }
                    285: 
                    286:     current_malloc_packets++;
                    287:     if (current_malloc_packets > maximum_malloc_packets)
                    288:         maximum_malloc_packets = current_malloc_packets;
                    289:     current_bytes_malloced += size;
                    290:     if (current_bytes_malloced > maximum_bytes_malloced)
                    291:         maximum_bytes_malloced = current_bytes_malloced;
                    292: 
                    293:     if (init_malloced_bodies)
                    294:         memset (result->body, 0xff, (int) size);
                    295: 
                    296:     return result->body;
                    297: }
                    298: 
                    299: /*
                    300:  *----------------------------------------------------------------------
                    301:  *
                    302:  * Tcl_DbCkfree - debugging ckfree
                    303:  *
                    304:  *        Verify that the low and high guards are intact, and if so
                    305:  *        then free the buffer else panic.
                    306:  *
                    307:  *        The guards are erased after being checked to catch duplicate
                    308:  *        frees.
                    309:  *
                    310:  *        The second and third arguments are file and line, these contain
                    311:  *        the filename and line number corresponding to the caller.
                    312:  *        These are sent by the ckfree macro; it uses the preprocessor
                    313:  *        autodefines __FILE__ and __LINE__.
                    314:  *
                    315:  *----------------------------------------------------------------------
                    316:  */
                    317: 
                    318: int
                    319: Tcl_DbCkfree(ptr, file, line)
                    320:     char *  ptr;
                    321:     char     *file;
                    322:     int       line;
                    323: {
                    324:     struct mem_header *memp = 0;  /* Must be zero for size calc */
                    325: 
                    326:     /*
                    327:      * Since header ptr is zero, body offset will be size
                    328:      */
                    329:     memp = (struct mem_header *)(((char *) ptr) - (int)memp->body);
                    330: 
                    331:     if (alloc_tracing)
                    332:         fprintf(stderr, "ckfree %lx %ld %s %d\n", memp->body, 
                    333:                 memp->length, file, line);
                    334: 
                    335:     if (validate_memory)
                    336:         Tcl_ValidateAllMemory (file, line);
                    337: 
                    338:     ValidateMemory (memp, file, line, TRUE);
                    339: 
                    340:     total_frees++;
                    341:     current_malloc_packets--;
                    342:     current_bytes_malloced -= memp->length;
                    343: 
                    344:     /*
                    345:      * Delink from allocated list
                    346:      */
                    347:     if (memp->flink != NULL)
                    348:         memp->flink->blink = memp->blink;
                    349:     if (memp->blink != NULL)
                    350:         memp->blink->flink = memp->flink;
                    351:     if (allocHead == memp)
                    352:         allocHead = memp->flink;
                    353:     free((char *) memp);
                    354:     return 0;
                    355: }
                    356: 
                    357: /*
                    358:  *----------------------------------------------------------------------
                    359:  *
                    360:  * MemoryCmd --
                    361:  *     Implements the TCL memory command:
                    362:  *       memory info
                    363:  *       memory display
                    364:  *       break_on_malloc count
                    365:  *       trace_on_at_malloc count
                    366:  *       trace on|off
                    367:  *       validate on|off
                    368:  *
                    369:  * Results:
                    370:  *     Standard TCL results.
                    371:  *
                    372:  *----------------------------------------------------------------------
                    373:  */
                    374:        /* ARGSUSED */
                    375: static int
                    376: MemoryCmd (clientData, interp, argc, argv)
                    377:     char       *clientData;
                    378:     Tcl_Interp *interp;
                    379:     int         argc;
                    380:     char      **argv;
                    381: {
                    382:     char *fileName;
                    383: 
                    384:     if (argc < 2) {
                    385:        Tcl_AppendResult(interp, "wrong # args:  should be \"",
                    386:                argv[0], " option [args..]\"", (char *) NULL);
                    387:        return TCL_ERROR;
                    388:     }
                    389: 
                    390:     if (strcmp(argv[1],"trace") == 0) {
                    391:         if (argc != 3) 
                    392:             goto bad_suboption;
                    393:         alloc_tracing = (strcmp(argv[2],"on") == 0);
                    394:         return TCL_OK;
                    395:     }
                    396:     if (strcmp(argv[1],"init") == 0) {
                    397:         if (argc != 3)
                    398:             goto bad_suboption;
                    399:         init_malloced_bodies = (strcmp(argv[2],"on") == 0);
                    400:         return TCL_OK;
                    401:     }
                    402:     if (strcmp(argv[1],"validate") == 0) {
                    403:         if (argc != 3)
                    404:              goto bad_suboption;
                    405:         validate_memory = (strcmp(argv[2],"on") == 0);
                    406:         return TCL_OK;
                    407:     }
                    408:     if (strcmp(argv[1],"trace_on_at_malloc") == 0) {
                    409:         if (argc != 3) 
                    410:             goto argError;
                    411:         if (Tcl_GetInt(interp, argv[2], &trace_on_at_malloc) != TCL_OK)
                    412:                 return TCL_ERROR;
                    413:          return TCL_OK;
                    414:     }
                    415:     if (strcmp(argv[1],"break_on_malloc") == 0) {
                    416:         if (argc != 3) 
                    417:             goto argError;
                    418:         if (Tcl_GetInt(interp, argv[2], &break_on_malloc) != TCL_OK)
                    419:                 return TCL_ERROR;
                    420:         return TCL_OK;
                    421:     }
                    422: 
                    423:     if (strcmp(argv[1],"info") == 0) {
                    424:         dump_memory_info(stdout);
                    425:         return TCL_OK;
                    426:     }
                    427:     if (strcmp(argv[1],"active") == 0) {
                    428:         if (argc != 3) {
                    429:            Tcl_AppendResult(interp, "wrong # args:  should be \"",
                    430:                    argv[0], " active file", (char *) NULL);
                    431:            return TCL_ERROR;
                    432:        }
                    433:         fileName = argv [2];
                    434:         if (fileName [0] == '~')
                    435:             if ((fileName = Tcl_TildeSubst (interp, fileName)) == NULL)
                    436:                 return TCL_ERROR;
                    437:         if (Tcl_DumpActiveMemory (fileName) != TCL_OK) {
                    438:            Tcl_AppendResult(interp, "error accessing ", argv[2], 
                    439:                    (char *) NULL);
                    440:            return TCL_ERROR;
                    441:        }
                    442:        return TCL_OK;
                    443:     }
                    444:     Tcl_AppendResult(interp, "bad option \"", argv[1],
                    445:            "\":  should be info, init, active, break_on_malloc, ",
                    446:            "trace_on_at_malloc, trace, or validate", (char *) NULL);
                    447:     return TCL_ERROR;
                    448: 
                    449: argError:
                    450:     Tcl_AppendResult(interp, "wrong # args:  should be \"", argv[0],
                    451:            " ", argv[1], "count\"", (char *) NULL);
                    452:     return TCL_ERROR;
                    453: 
                    454: bad_suboption:
                    455:     Tcl_AppendResult(interp, "wrong # args:  should be \"", argv[0],
                    456:            " ", argv[1], " on|off\"", (char *) NULL);
                    457:     return TCL_ERROR;
                    458: }
                    459: 
                    460: /*
                    461:  *----------------------------------------------------------------------
                    462:  *
                    463:  * Tcl_InitMemory --
                    464:  *     Initialize the memory command.
                    465:  *
                    466:  *----------------------------------------------------------------------
                    467:  */
                    468: void
                    469: Tcl_InitMemory(interp)
                    470:     Tcl_Interp *interp;
                    471: {
                    472: Tcl_CreateCommand (interp, "memory", MemoryCmd, (ClientData)NULL, 
                    473:                   (void (*)())NULL);
                    474: }
                    475: 
                    476: #else
                    477: 
                    478: 
                    479: /*
                    480:  *----------------------------------------------------------------------
                    481:  *
                    482:  * Tcl_Ckalloc --
                    483:  *     Interface to malloc when TCL_MEM_DEBUG is disabled.  It does check
                    484:  *     that memory was actually allocated.
                    485:  *
                    486:  *----------------------------------------------------------------------
                    487:  */
                    488: VOID *
                    489: Tcl_Ckalloc (size)
                    490:     unsigned int size;
                    491: {
                    492:         char *result;
                    493: 
                    494:         result = malloc(size);
                    495:         if (result == NULL) 
                    496:                 panic("unable to alloc %d bytes", size);
                    497:         return result;
                    498: }
                    499: 
                    500: /*
                    501:  *----------------------------------------------------------------------
                    502:  *
                    503:  * TckCkfree --
                    504:  *     Interface to free when TCL_MEM_DEBUG is disabled.  Done here rather
                    505:  *     in the macro to keep some modules from being compiled with 
                    506:  *     TCL_MEM_DEBUG enabled and some with it disabled.
                    507:  *
                    508:  *----------------------------------------------------------------------
                    509:  */
                    510: void
                    511: Tcl_Ckfree (ptr)
                    512:     VOID *ptr;
                    513: {
                    514:         free (ptr);
                    515: }
                    516: 
                    517: /*
                    518:  *----------------------------------------------------------------------
                    519:  *
                    520:  * Tcl_InitMemory --
                    521:  *     Dummy initialization for memory command, which is only available 
                    522:  *     if TCL_MEM_DEBUG is on.
                    523:  *
                    524:  *----------------------------------------------------------------------
                    525:  */
                    526:        /* ARGSUSED */
                    527: void
                    528: Tcl_InitMemory(interp)
                    529:     Tcl_Interp *interp;
                    530: {
                    531: }
                    532: 
                    533: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.