Annotation of micropolis/src/tcl/tclckall.c, revision 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.