diff options
Diffstat (limited to 'tcl8.6/generic/tclCkalloc.c')
-rw-r--r-- | tcl8.6/generic/tclCkalloc.c | 1328 |
1 files changed, 0 insertions, 1328 deletions
diff --git a/tcl8.6/generic/tclCkalloc.c b/tcl8.6/generic/tclCkalloc.c deleted file mode 100644 index 70e64f0..0000000 --- a/tcl8.6/generic/tclCkalloc.c +++ /dev/null @@ -1,1328 +0,0 @@ -/* - * tclCkalloc.c -- - * - * Interface to malloc and free that provides support for debugging - * problems involving overwritten, double freeing memory and loss of - * memory. - * - * Copyright (c) 1991-1994 The Regents of the University of California. - * Copyright (c) 1994-1997 Sun Microsystems, Inc. - * Copyright (c) 1998-1999 by Scriptics Corporation. - * - * See the file "license.terms" for information on usage and redistribution of - * this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * This code contributed by Karl Lehenbauer and Mark Diekhans - */ - -#include "tclInt.h" - -#define FALSE 0 -#define TRUE 1 - -#undef Tcl_Alloc -#undef Tcl_Free -#undef Tcl_Realloc -#undef Tcl_AttemptAlloc -#undef Tcl_AttemptRealloc - -#ifdef TCL_MEM_DEBUG - -/* - * One of the following structures is allocated each time the - * "memory tag" command is invoked, to hold the current tag. - */ - -typedef struct MemTag { - int refCount; /* Number of mem_headers referencing this - * tag. */ - char string[1]; /* Actual size of string will be as large as - * needed for actual tag. This must be the - * last field in the structure. */ -} MemTag; - -#define TAG_SIZE(bytesInString) ((unsigned) ((TclOffset(MemTag, string) + 1) + bytesInString)) - -static MemTag *curTagPtr = NULL;/* Tag to use in all future mem_headers (set - * by "memory tag" command). */ - -/* - * One of the following structures is allocated just before each dynamically - * allocated chunk of memory, both to record information about the chunk and - * to help detect chunk under-runs. - */ - -#define LOW_GUARD_SIZE (8 + (32 - (sizeof(long) + sizeof(int)))%8) -struct mem_header { - struct mem_header *flink; - struct mem_header *blink; - MemTag *tagPtr; /* Tag from "memory tag" command; may be - * NULL. */ - const char *file; - long length; - int line; - unsigned char low_guard[LOW_GUARD_SIZE]; - /* Aligns body on 8-byte boundary, plus - * provides at least 8 additional guard bytes - * to detect underruns. */ - char body[1]; /* First byte of client's space. Actual size - * of this field will be larger than one. */ -}; - -static struct mem_header *allocHead = NULL; /* List of allocated structures */ - -#define GUARD_VALUE 0141 - -/* - * The following macro determines the amount of guard space *above* each chunk - * of memory. - */ - -#define HIGH_GUARD_SIZE 8 - -/* - * The following macro computes the offset of the "body" field within - * mem_header. It is used to get back to the header pointer from the body - * pointer that's used by clients. - */ - -#define BODY_OFFSET \ - ((size_t) (&((struct mem_header *) 0)->body)) - -static int total_mallocs = 0; -static int total_frees = 0; -static size_t current_bytes_malloced = 0; -static size_t maximum_bytes_malloced = 0; -static int current_malloc_packets = 0; -static int maximum_malloc_packets = 0; -static int break_on_malloc = 0; -static int trace_on_at_malloc = 0; -static int alloc_tracing = FALSE; -static int init_malloced_bodies = TRUE; -#ifdef MEM_VALIDATE -static int validate_memory = TRUE; -#else -static int validate_memory = FALSE; -#endif - -/* - * The following variable indicates to TclFinalizeMemorySubsystem() that it - * should dump out the state of memory before exiting. If the value is - * non-NULL, it gives the name of the file in which to dump memory usage - * information. - */ - -char *tclMemDumpFileName = NULL; - -static char *onExitMemDumpFileName = NULL; -static char dumpFile[100]; /* Records where to dump memory allocation - * information. */ - -/* - * Mutex to serialize allocations. This is a low-level mutex that must be - * explicitly initialized. This is necessary because the self initializing - * mutexes use ckalloc... - */ - -static Tcl_Mutex *ckallocMutexPtr; -static int ckallocInit = 0; - -/* - * Prototypes for procedures defined in this file: - */ - -static int CheckmemCmd(ClientData clientData, Tcl_Interp *interp, - int argc, const char *argv[]); -static int MemoryCmd(ClientData clientData, Tcl_Interp *interp, - int argc, const char *argv[]); -static void ValidateMemory(struct mem_header *memHeaderP, - const char *file, int line, int nukeGuards); - -/* - *---------------------------------------------------------------------- - * - * TclInitDbCkalloc -- - * - * Initialize the locks used by the allocator. This is only appropriate - * to call in a single threaded environment, such as during - * TclInitSubsystems. - * - *---------------------------------------------------------------------- - */ - -void -TclInitDbCkalloc(void) -{ - if (!ckallocInit) { - ckallocInit = 1; - ckallocMutexPtr = Tcl_GetAllocMutex(); -#ifndef TCL_THREADS - /* Silence compiler warning */ - (void)ckallocMutexPtr; -#endif - } -} - -/* - *---------------------------------------------------------------------- - * - * TclDumpMemoryInfo -- - * - * Display the global memory management statistics. - * - *---------------------------------------------------------------------- - */ - -int -TclDumpMemoryInfo( - ClientData clientData, - int flags) -{ - char buf[1024]; - - if (clientData == NULL) { - return 0; - } - sprintf(buf, - "total mallocs %10d\n" - "total frees %10d\n" - "current packets allocated %10d\n" - "current bytes allocated %10lu\n" - "maximum packets allocated %10d\n" - "maximum bytes allocated %10lu\n", - total_mallocs, - total_frees, - current_malloc_packets, - (unsigned long)current_bytes_malloced, - maximum_malloc_packets, - (unsigned long)maximum_bytes_malloced); - if (flags == 0) { - fprintf((FILE *)clientData, "%s", buf); - } else { - /* Assume objPtr to append to */ - Tcl_AppendToObj((Tcl_Obj *) clientData, buf, -1); - } - return 1; -} - -/* - *---------------------------------------------------------------------- - * - * ValidateMemory -- - * - * Validate memory guard zones for a particular chunk of allocated - * memory. - * - * Results: - * None. - * - * Side effects: - * Prints validation information about the allocated memory to stderr. - * - *---------------------------------------------------------------------- - */ - -static void -ValidateMemory( - struct mem_header *memHeaderP, - /* Memory chunk to validate */ - const char *file, /* File containing the call to - * Tcl_ValidateAllMemory */ - int line, /* Line number of call to - * Tcl_ValidateAllMemory */ - int nukeGuards) /* If non-zero, indicates that the memory - * guards are to be reset to 0 after they have - * been printed */ -{ - unsigned char *hiPtr; - size_t idx; - int guard_failed = FALSE; - int byte; - - for (idx = 0; idx < LOW_GUARD_SIZE; idx++) { - byte = *(memHeaderP->low_guard + idx); - if (byte != GUARD_VALUE) { - guard_failed = TRUE; - fflush(stdout); - byte &= 0xff; - fprintf(stderr, "low guard byte %d is 0x%x \t%c\n", (int)idx, byte, - (isprint(UCHAR(byte)) ? byte : ' ')); /* INTL: bytes */ - } - } - if (guard_failed) { - TclDumpMemoryInfo((ClientData) stderr, 0); - fprintf(stderr, "low guard failed at %lx, %s %d\n", - (long unsigned) memHeaderP->body, file, line); - fflush(stderr); /* In case name pointer is bad. */ - fprintf(stderr, "%ld bytes allocated at (%s %d)\n", memHeaderP->length, - memHeaderP->file, memHeaderP->line); - Tcl_Panic("Memory validation failure"); - } - - hiPtr = (unsigned char *)memHeaderP->body + memHeaderP->length; - for (idx = 0; idx < HIGH_GUARD_SIZE; idx++) { - byte = *(hiPtr + idx); - if (byte != GUARD_VALUE) { - guard_failed = TRUE; - fflush(stdout); - byte &= 0xff; - fprintf(stderr, "hi guard byte %d is 0x%x \t%c\n", (int)idx, byte, - (isprint(UCHAR(byte)) ? byte : ' ')); /* INTL: bytes */ - } - } - - if (guard_failed) { - TclDumpMemoryInfo((ClientData) stderr, 0); - fprintf(stderr, "high guard failed at %lx, %s %d\n", - (long unsigned) memHeaderP->body, file, line); - fflush(stderr); /* In case name pointer is bad. */ - fprintf(stderr, "%ld bytes allocated at (%s %d)\n", - memHeaderP->length, memHeaderP->file, - memHeaderP->line); - Tcl_Panic("Memory validation failure"); - } - - if (nukeGuards) { - memset(memHeaderP->low_guard, 0, LOW_GUARD_SIZE); - memset(hiPtr, 0, HIGH_GUARD_SIZE); - } - -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_ValidateAllMemory -- - * - * Validate memory guard regions for all allocated memory. - * - * Results: - * None. - * - * Side effects: - * Displays memory validation information to stderr. - * - *---------------------------------------------------------------------- - */ - -void -Tcl_ValidateAllMemory( - const char *file, /* File from which Tcl_ValidateAllMemory was - * called. */ - int line) /* Line number of call to - * Tcl_ValidateAllMemory */ -{ - struct mem_header *memScanP; - - if (!ckallocInit) { - TclInitDbCkalloc(); - } - Tcl_MutexLock(ckallocMutexPtr); - for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) { - ValidateMemory(memScanP, file, line, FALSE); - } - Tcl_MutexUnlock(ckallocMutexPtr); -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_DumpActiveMemory -- - * - * Displays all allocated memory to a file; if no filename is given, - * information will be written to stderr. - * - * Results: - * Return TCL_ERROR if an error accessing the file occurs, `errno' will - * have the file error number left in it. - * - *---------------------------------------------------------------------- - */ - -int -Tcl_DumpActiveMemory( - const char *fileName) /* Name of the file to write info to */ -{ - FILE *fileP; - struct mem_header *memScanP; - char *address; - - if (fileName == NULL) { - fileP = stderr; - } else { - fileP = fopen(fileName, "w"); - if (fileP == NULL) { - return TCL_ERROR; - } - } - - Tcl_MutexLock(ckallocMutexPtr); - for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) { - address = &memScanP->body[0]; - fprintf(fileP, "%8lx - %8lx %7ld @ %s %d %s", - (long unsigned) address, - (long unsigned) address + memScanP->length - 1, - memScanP->length, memScanP->file, memScanP->line, - (memScanP->tagPtr == NULL) ? "" : memScanP->tagPtr->string); - (void) fputc('\n', fileP); - } - Tcl_MutexUnlock(ckallocMutexPtr); - - if (fileP != stderr) { - fclose(fileP); - } - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_DbCkalloc - debugging ckalloc - * - * Allocate the requested amount of space plus some extra for guard bands - * at both ends of the request, plus a size, panicing if there isn't - * enough space, then write in the guard bands and return the address of - * the space in the middle that the user asked for. - * - * The second and third arguments are file and line, these contain the - * filename and line number corresponding to the caller. These are sent - * by the ckalloc macro; it uses the preprocessor autodefines __FILE__ - * and __LINE__. - * - *---------------------------------------------------------------------- - */ - -char * -Tcl_DbCkalloc( - unsigned int size, - const char *file, - int line) -{ - struct mem_header *result = NULL; - - if (validate_memory) { - Tcl_ValidateAllMemory(file, line); - } - - /* Don't let size argument to TclpAlloc overflow */ - if (size <= UINT_MAX - HIGH_GUARD_SIZE -sizeof(struct mem_header)) { - result = (struct mem_header *) TclpAlloc((unsigned)size + - sizeof(struct mem_header) + HIGH_GUARD_SIZE); - } - if (result == NULL) { - fflush(stdout); - TclDumpMemoryInfo((ClientData) stderr, 0); - Tcl_Panic("unable to alloc %u bytes, %s line %d", size, file, line); - } - - /* - * Fill in guard zones and size. Also initialize the contents of the block - * with bogus bytes to detect uses of initialized data. Link into - * allocated list. - */ - - if (init_malloced_bodies) { - memset(result, GUARD_VALUE, - size + sizeof(struct mem_header) + HIGH_GUARD_SIZE); - } else { - memset(result->low_guard, GUARD_VALUE, LOW_GUARD_SIZE); - memset(result->body + size, GUARD_VALUE, HIGH_GUARD_SIZE); - } - if (!ckallocInit) { - TclInitDbCkalloc(); - } - Tcl_MutexLock(ckallocMutexPtr); - result->length = size; - result->tagPtr = curTagPtr; - if (curTagPtr != NULL) { - curTagPtr->refCount++; - } - result->file = file; - result->line = line; - result->flink = allocHead; - result->blink = NULL; - - if (allocHead != NULL) { - allocHead->blink = result; - } - allocHead = result; - - total_mallocs++; - if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) { - (void) fflush(stdout); - fprintf(stderr, "reached malloc trace enable point (%d)\n", - total_mallocs); - fflush(stderr); - alloc_tracing = TRUE; - trace_on_at_malloc = 0; - } - - if (alloc_tracing) { - fprintf(stderr,"ckalloc %lx %u %s %d\n", - (long unsigned int) result->body, size, file, line); - } - - if (break_on_malloc && (total_mallocs >= break_on_malloc)) { - break_on_malloc = 0; - (void) fflush(stdout); - Tcl_Panic("reached malloc break limit (%d)", total_mallocs); - } - - current_malloc_packets++; - if (current_malloc_packets > maximum_malloc_packets) { - maximum_malloc_packets = current_malloc_packets; - } - current_bytes_malloced += size; - if (current_bytes_malloced > maximum_bytes_malloced) { - maximum_bytes_malloced = current_bytes_malloced; - } - - Tcl_MutexUnlock(ckallocMutexPtr); - - return result->body; -} - -char * -Tcl_AttemptDbCkalloc( - unsigned int size, - const char *file, - int line) -{ - struct mem_header *result = NULL; - - if (validate_memory) { - Tcl_ValidateAllMemory(file, line); - } - - /* Don't let size argument to TclpAlloc overflow */ - if (size <= UINT_MAX - HIGH_GUARD_SIZE - sizeof(struct mem_header)) { - result = (struct mem_header *) TclpAlloc((unsigned)size + - sizeof(struct mem_header) + HIGH_GUARD_SIZE); - } - if (result == NULL) { - fflush(stdout); - TclDumpMemoryInfo((ClientData) stderr, 0); - return NULL; - } - - /* - * Fill in guard zones and size. Also initialize the contents of the block - * with bogus bytes to detect uses of initialized data. Link into - * allocated list. - */ - if (init_malloced_bodies) { - memset(result, GUARD_VALUE, - size + sizeof(struct mem_header) + HIGH_GUARD_SIZE); - } else { - memset(result->low_guard, GUARD_VALUE, LOW_GUARD_SIZE); - memset(result->body + size, GUARD_VALUE, HIGH_GUARD_SIZE); - } - if (!ckallocInit) { - TclInitDbCkalloc(); - } - Tcl_MutexLock(ckallocMutexPtr); - result->length = size; - result->tagPtr = curTagPtr; - if (curTagPtr != NULL) { - curTagPtr->refCount++; - } - result->file = file; - result->line = line; - result->flink = allocHead; - result->blink = NULL; - - if (allocHead != NULL) { - allocHead->blink = result; - } - allocHead = result; - - total_mallocs++; - if (trace_on_at_malloc && (total_mallocs >= trace_on_at_malloc)) { - (void) fflush(stdout); - fprintf(stderr, "reached malloc trace enable point (%d)\n", - total_mallocs); - fflush(stderr); - alloc_tracing = TRUE; - trace_on_at_malloc = 0; - } - - if (alloc_tracing) { - fprintf(stderr,"ckalloc %lx %u %s %d\n", - (long unsigned int) result->body, size, file, line); - } - - if (break_on_malloc && (total_mallocs >= break_on_malloc)) { - break_on_malloc = 0; - (void) fflush(stdout); - Tcl_Panic("reached malloc break limit (%d)", total_mallocs); - } - - current_malloc_packets++; - if (current_malloc_packets > maximum_malloc_packets) { - maximum_malloc_packets = current_malloc_packets; - } - current_bytes_malloced += size; - if (current_bytes_malloced > maximum_bytes_malloced) { - maximum_bytes_malloced = current_bytes_malloced; - } - - Tcl_MutexUnlock(ckallocMutexPtr); - - return result->body; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_DbCkfree - debugging ckfree - * - * Verify that the low and high guards are intact, and if so then free - * the buffer else Tcl_Panic. - * - * The guards are erased after being checked to catch duplicate frees. - * - * The second and third arguments are file and line, these contain the - * filename and line number corresponding to the caller. These are sent - * by the ckfree macro; it uses the preprocessor autodefines __FILE__ and - * __LINE__. - * - *---------------------------------------------------------------------- - */ - -void -Tcl_DbCkfree( - char *ptr, - const char *file, - int line) -{ - struct mem_header *memp; - - if (ptr == NULL) { - return; - } - - /* - * The following cast is *very* tricky. Must convert the pointer to an - * integer before doing arithmetic on it, because otherwise the arithmetic - * will be done differently (and incorrectly) on word-addressed machines - * such as Crays (will subtract only bytes, even though BODY_OFFSET is in - * words on these machines). - */ - - memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET); - - if (alloc_tracing) { - fprintf(stderr, "ckfree %lx %ld %s %d\n", - (long unsigned int) memp->body, memp->length, file, line); - } - - if (validate_memory) { - Tcl_ValidateAllMemory(file, line); - } - - Tcl_MutexLock(ckallocMutexPtr); - ValidateMemory(memp, file, line, TRUE); - if (init_malloced_bodies) { - memset(ptr, GUARD_VALUE, (size_t) memp->length); - } - - total_frees++; - current_malloc_packets--; - current_bytes_malloced -= memp->length; - - if (memp->tagPtr != NULL) { - memp->tagPtr->refCount--; - if ((memp->tagPtr->refCount == 0) && (curTagPtr != memp->tagPtr)) { - TclpFree((char *) memp->tagPtr); - } - } - - /* - * Delink from allocated list - */ - - if (memp->flink != NULL) { - memp->flink->blink = memp->blink; - } - if (memp->blink != NULL) { - memp->blink->flink = memp->flink; - } - if (allocHead == memp) { - allocHead = memp->flink; - } - TclpFree((char *) memp); - Tcl_MutexUnlock(ckallocMutexPtr); -} - -/* - *-------------------------------------------------------------------- - * - * Tcl_DbCkrealloc - debugging ckrealloc - * - * Reallocate a chunk of memory by allocating a new one of the right - * size, copying the old data to the new location, and then freeing the - * old memory space, using all the memory checking features of this - * package. - * - *-------------------------------------------------------------------- - */ - -char * -Tcl_DbCkrealloc( - char *ptr, - unsigned int size, - const char *file, - int line) -{ - char *newPtr; - unsigned int copySize; - struct mem_header *memp; - - if (ptr == NULL) { - return Tcl_DbCkalloc(size, file, line); - } - - /* - * See comment from Tcl_DbCkfree before you change the following line. - */ - - memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET); - - copySize = size; - if (copySize > (unsigned int) memp->length) { - copySize = memp->length; - } - newPtr = Tcl_DbCkalloc(size, file, line); - memcpy(newPtr, ptr, (size_t) copySize); - Tcl_DbCkfree(ptr, file, line); - return newPtr; -} - -char * -Tcl_AttemptDbCkrealloc( - char *ptr, - unsigned int size, - const char *file, - int line) -{ - char *newPtr; - unsigned int copySize; - struct mem_header *memp; - - if (ptr == NULL) { - return Tcl_AttemptDbCkalloc(size, file, line); - } - - /* - * See comment from Tcl_DbCkfree before you change the following line. - */ - - memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET); - - copySize = size; - if (copySize > (unsigned int) memp->length) { - copySize = memp->length; - } - newPtr = Tcl_AttemptDbCkalloc(size, file, line); - if (newPtr == NULL) { - return NULL; - } - memcpy(newPtr, ptr, (size_t) copySize); - Tcl_DbCkfree(ptr, file, line); - return newPtr; -} - - -/* - *---------------------------------------------------------------------- - * - * Tcl_Alloc, et al. -- - * - * These functions are defined in terms of the debugging versions when - * TCL_MEM_DEBUG is set. - * - * Results: - * Same as the debug versions. - * - * Side effects: - * Same as the debug versions. - * - *---------------------------------------------------------------------- - */ - -char * -Tcl_Alloc( - unsigned int size) -{ - return Tcl_DbCkalloc(size, "unknown", 0); -} - -char * -Tcl_AttemptAlloc( - unsigned int size) -{ - return Tcl_AttemptDbCkalloc(size, "unknown", 0); -} - -void -Tcl_Free( - char *ptr) -{ - Tcl_DbCkfree(ptr, "unknown", 0); -} - -char * -Tcl_Realloc( - char *ptr, - unsigned int size) -{ - return Tcl_DbCkrealloc(ptr, size, "unknown", 0); -} -char * -Tcl_AttemptRealloc( - char *ptr, - unsigned int size) -{ - return Tcl_AttemptDbCkrealloc(ptr, size, "unknown", 0); -} - -/* - *---------------------------------------------------------------------- - * - * MemoryCmd -- - * - * Implements the Tcl "memory" command, which provides Tcl-level control - * of Tcl memory debugging information. - * memory active $file - * memory break_on_malloc $count - * memory info - * memory init on|off - * memory onexit $file - * memory tag $string - * memory trace on|off - * memory trace_on_at_malloc $count - * memory validate on|off - * - * Results: - * Standard TCL results. - * - *---------------------------------------------------------------------- - */ - /* ARGSUSED */ -static int -MemoryCmd( - ClientData clientData, - Tcl_Interp *interp, - int argc, - const char *argv[]) -{ - const char *fileName; - FILE *fileP; - Tcl_DString buffer; - int result; - size_t len; - - if (argc < 2) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "wrong # args: should be \"%s option [args..]\"", argv[0])); - return TCL_ERROR; - } - - if (strcmp(argv[1], "active") == 0 || strcmp(argv[1], "display") == 0) { - if (argc != 3) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "wrong # args: should be \"%s %s file\"", - argv[0], argv[1])); - return TCL_ERROR; - } - fileName = Tcl_TranslateFileName(interp, argv[2], &buffer); - if (fileName == NULL) { - return TCL_ERROR; - } - result = Tcl_DumpActiveMemory(fileName); - Tcl_DStringFree(&buffer); - if (result != TCL_OK) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf("error accessing %s: %s", - argv[2], Tcl_PosixError(interp))); - return TCL_ERROR; - } - return TCL_OK; - } - if (strcmp(argv[1],"break_on_malloc") == 0) { - if (argc != 3) { - goto argError; - } - if (Tcl_GetInt(interp, argv[2], &break_on_malloc) != TCL_OK) { - return TCL_ERROR; - } - return TCL_OK; - } - if (strcmp(argv[1],"info") == 0) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10lu\n%-25s %10d\n%-25s %10lu\n", - "total mallocs", total_mallocs, "total frees", total_frees, - "current packets allocated", current_malloc_packets, - "current bytes allocated", (unsigned long)current_bytes_malloced, - "maximum packets allocated", maximum_malloc_packets, - "maximum bytes allocated", (unsigned long)maximum_bytes_malloced)); - return TCL_OK; - } - if (strcmp(argv[1], "init") == 0) { - if (argc != 3) { - goto bad_suboption; - } - init_malloced_bodies = (strcmp(argv[2],"on") == 0); - return TCL_OK; - } - if (strcmp(argv[1], "objs") == 0) { - if (argc != 3) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "wrong # args: should be \"%s objs file\"", argv[0])); - return TCL_ERROR; - } - fileName = Tcl_TranslateFileName(interp, argv[2], &buffer); - if (fileName == NULL) { - return TCL_ERROR; - } - fileP = fopen(fileName, "w"); - if (fileP == NULL) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "cannot open output file: %s", - Tcl_PosixError(interp))); - return TCL_ERROR; - } - TclDbDumpActiveObjects(fileP); - fclose(fileP); - Tcl_DStringFree(&buffer); - return TCL_OK; - } - if (strcmp(argv[1],"onexit") == 0) { - if (argc != 3) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "wrong # args: should be \"%s onexit file\"", argv[0])); - return TCL_ERROR; - } - fileName = Tcl_TranslateFileName(interp, argv[2], &buffer); - if (fileName == NULL) { - return TCL_ERROR; - } - onExitMemDumpFileName = dumpFile; - strcpy(onExitMemDumpFileName,fileName); - Tcl_DStringFree(&buffer); - return TCL_OK; - } - if (strcmp(argv[1],"tag") == 0) { - if (argc != 3) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "wrong # args: should be \"%s tag string\"", argv[0])); - return TCL_ERROR; - } - if ((curTagPtr != NULL) && (curTagPtr->refCount == 0)) { - TclpFree((char *) curTagPtr); - } - len = strlen(argv[2]); - curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(len)); - curTagPtr->refCount = 0; - memcpy(curTagPtr->string, argv[2], len + 1); - return TCL_OK; - } - if (strcmp(argv[1],"trace") == 0) { - if (argc != 3) { - goto bad_suboption; - } - alloc_tracing = (strcmp(argv[2],"on") == 0); - return TCL_OK; - } - - if (strcmp(argv[1],"trace_on_at_malloc") == 0) { - if (argc != 3) { - goto argError; - } - if (Tcl_GetInt(interp, argv[2], &trace_on_at_malloc) != TCL_OK) { - return TCL_ERROR; - } - return TCL_OK; - } - if (strcmp(argv[1],"validate") == 0) { - if (argc != 3) { - goto bad_suboption; - } - validate_memory = (strcmp(argv[2],"on") == 0); - return TCL_OK; - } - - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "bad option \"%s\": should be active, break_on_malloc, info, " - "init, objs, onexit, tag, trace, trace_on_at_malloc, or validate", - argv[1])); - return TCL_ERROR; - - argError: - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "wrong # args: should be \"%s %s count\"", argv[0], argv[1])); - return TCL_ERROR; - - bad_suboption: - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "wrong # args: should be \"%s %s on|off\"", argv[0], argv[1])); - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * CheckmemCmd -- - * - * This is the command procedure for the "checkmem" command, which causes - * the application to exit after printing information about memory usage - * to the file passed to this command as its first argument. - * - * Results: - * Returns a standard Tcl completion code. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -CheckmemCmd( - ClientData clientData, /* Not used. */ - Tcl_Interp *interp, /* Interpreter for evaluation. */ - int argc, /* Number of arguments. */ - const char *argv[]) /* String values of arguments. */ -{ - if (argc != 2) { - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "wrong # args: should be \"%s fileName\"", argv[0])); - return TCL_ERROR; - } - tclMemDumpFileName = dumpFile; - strcpy(tclMemDumpFileName, argv[1]); - return TCL_OK; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_InitMemory -- - * - * Create the "memory" and "checkmem" commands in the given interpreter. - * - * Results: - * None. - * - * Side effects: - * New commands are added to the interpreter. - * - *---------------------------------------------------------------------- - */ - -void -Tcl_InitMemory( - Tcl_Interp *interp) /* Interpreter in which commands should be - * added */ -{ - TclInitDbCkalloc(); - Tcl_CreateCommand(interp, "memory", MemoryCmd, NULL, NULL); - Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, NULL, NULL); -} - - -#else /* TCL_MEM_DEBUG */ - -/* This is the !TCL_MEM_DEBUG case */ - -#undef Tcl_InitMemory -#undef Tcl_DumpActiveMemory -#undef Tcl_ValidateAllMemory - - -/* - *---------------------------------------------------------------------- - * - * Tcl_Alloc -- - * - * Interface to TclpAlloc when TCL_MEM_DEBUG is disabled. It does check - * that memory was actually allocated. - * - *---------------------------------------------------------------------- - */ - -char * -Tcl_Alloc( - unsigned int size) -{ - char *result; - - result = TclpAlloc(size); - - /* - * Most systems will not alloc(0), instead bumping it to one so that NULL - * isn't returned. Some systems (AIX, Tru64) will alloc(0) by returning - * NULL, so we have to check that the NULL we get is not in response to - * alloc(0). - * - * The ANSI spec actually says that systems either return NULL *or* a - * special pointer on failure, but we only check for NULL - */ - - if ((result == NULL) && size) { - Tcl_Panic("unable to alloc %u bytes", size); - } - return result; -} - -char * -Tcl_DbCkalloc( - unsigned int size, - const char *file, - int line) -{ - char *result; - - result = (char *) TclpAlloc(size); - - if ((result == NULL) && size) { - fflush(stdout); - Tcl_Panic("unable to alloc %u bytes, %s line %d", size, file, line); - } - return result; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_AttemptAlloc -- - * - * Interface to TclpAlloc when TCL_MEM_DEBUG is disabled. It does not - * check that memory was actually allocated. - * - *---------------------------------------------------------------------- - */ - -char * -Tcl_AttemptAlloc( - unsigned int size) -{ - char *result; - - result = TclpAlloc(size); - return result; -} - -char * -Tcl_AttemptDbCkalloc( - unsigned int size, - const char *file, - int line) -{ - char *result; - - result = (char *) TclpAlloc(size); - return result; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_Realloc -- - * - * Interface to TclpRealloc when TCL_MEM_DEBUG is disabled. It does check - * that memory was actually allocated. - * - *---------------------------------------------------------------------- - */ - -char * -Tcl_Realloc( - char *ptr, - unsigned int size) -{ - char *result; - - result = TclpRealloc(ptr, size); - - if ((result == NULL) && size) { - Tcl_Panic("unable to realloc %u bytes", size); - } - return result; -} - -char * -Tcl_DbCkrealloc( - char *ptr, - unsigned int size, - const char *file, - int line) -{ - char *result; - - result = (char *) TclpRealloc(ptr, size); - - if ((result == NULL) && size) { - fflush(stdout); - Tcl_Panic("unable to realloc %u bytes, %s line %d", size, file, line); - } - return result; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_AttemptRealloc -- - * - * Interface to TclpRealloc when TCL_MEM_DEBUG is disabled. It does not - * check that memory was actually allocated. - * - *---------------------------------------------------------------------- - */ - -char * -Tcl_AttemptRealloc( - char *ptr, - unsigned int size) -{ - char *result; - - result = TclpRealloc(ptr, size); - return result; -} - -char * -Tcl_AttemptDbCkrealloc( - char *ptr, - unsigned int size, - const char *file, - int line) -{ - char *result; - - result = (char *) TclpRealloc(ptr, size); - return result; -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_Free -- - * - * Interface to TclpFree when TCL_MEM_DEBUG is disabled. Done here rather - * in the macro to keep some modules from being compiled with - * TCL_MEM_DEBUG enabled and some with it disabled. - * - *---------------------------------------------------------------------- - */ - -void -Tcl_Free( - char *ptr) -{ - TclpFree(ptr); -} - -void -Tcl_DbCkfree( - char *ptr, - const char *file, - int line) -{ - TclpFree(ptr); -} - -/* - *---------------------------------------------------------------------- - * - * Tcl_InitMemory -- - * - * Dummy initialization for memory command, which is only available if - * TCL_MEM_DEBUG is on. - * - *---------------------------------------------------------------------- - */ - /* ARGSUSED */ -void -Tcl_InitMemory( - Tcl_Interp *interp) -{ -} - -int -Tcl_DumpActiveMemory( - const char *fileName) -{ - return TCL_OK; -} - -void -Tcl_ValidateAllMemory( - const char *file, - int line) -{ -} - -int -TclDumpMemoryInfo( - ClientData clientData, - int flags) -{ - return 1; -} - -#endif /* TCL_MEM_DEBUG */ - -/* - *--------------------------------------------------------------------------- - * - * TclFinalizeMemorySubsystem -- - * - * This procedure is called to finalize all the structures that are used - * by the memory allocator on a per-process basis. - * - * Results: - * None. - * - * Side effects: - * This subsystem is self-initializing, since memory can be allocated - * before Tcl is formally initialized. After this call, this subsystem - * has been reset to its initial state and is usable again. - * - *--------------------------------------------------------------------------- - */ - -void -TclFinalizeMemorySubsystem(void) -{ -#ifdef TCL_MEM_DEBUG - if (tclMemDumpFileName != NULL) { - Tcl_DumpActiveMemory(tclMemDumpFileName); - } else if (onExitMemDumpFileName != NULL) { - Tcl_DumpActiveMemory(onExitMemDumpFileName); - } - - Tcl_MutexLock(ckallocMutexPtr); - - if (curTagPtr != NULL) { - TclpFree((char *) curTagPtr); - curTagPtr = NULL; - } - allocHead = NULL; - - Tcl_MutexUnlock(ckallocMutexPtr); -#endif - -#if USE_TCLALLOC - TclFinalizeAllocSubsystem(); -#endif -} - -/* - * Local Variables: - * mode: c - * c-basic-offset: 4 - * fill-column: 78 - * tab-width: 8 - * indent-tabs-mode: nil - * End: - */ |