diff options
Diffstat (limited to 'generic/tclCkalloc.c')
| -rw-r--r-- | generic/tclCkalloc.c | 269 | 
1 files changed, 156 insertions, 113 deletions
| diff --git a/generic/tclCkalloc.c b/generic/tclCkalloc.c index ee259d4..70e64f0 100644 --- a/generic/tclCkalloc.c +++ b/generic/tclCkalloc.c @@ -13,8 +13,6 @@   * this file, and for a DISCLAIMER OF ALL WARRANTIES.   *   * This code contributed by Karl Lehenbauer and Mark Diekhans - * - * RCS: @(#) $Id: tclCkalloc.c,v 1.32 2007/04/23 20:33:56 das Exp $   */  #include "tclInt.h" @@ -22,6 +20,12 @@  #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  /* @@ -32,12 +36,12 @@  typedef struct MemTag {      int refCount;		/* Number of mem_headers referencing this  				 * tag. */ -    char string[4];		/* Actual size of string will be as large as +    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) sizeof(MemTag) + bytesInString - 3) +#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). */ @@ -54,7 +58,7 @@ struct mem_header {      struct mem_header *blink;      MemTag *tagPtr;		/* Tag from "memory tag" command; may be  				 * NULL. */ -    CONST char *file; +    const char *file;      long length;      int line;      unsigned char low_guard[LOW_GUARD_SIZE]; @@ -83,12 +87,12 @@ static struct mem_header *allocHead = NULL;  /* List of allocated structures */   */  #define BODY_OFFSET \ -	((unsigned long) (&((struct mem_header *) 0)->body)) +	((size_t) (&((struct mem_header *) 0)->body))  static int total_mallocs = 0;  static int total_frees = 0; -static int current_bytes_malloced = 0; -static int maximum_bytes_malloced = 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; @@ -128,11 +132,11 @@ static int ckallocInit = 0;   */  static int		CheckmemCmd(ClientData clientData, Tcl_Interp *interp, -			    int argc, CONST char *argv[]); +			    int argc, const char *argv[]);  static int		MemoryCmd(ClientData clientData, Tcl_Interp *interp, -			    int argc, CONST char *argv[]); +			    int argc, const char *argv[]);  static void		ValidateMemory(struct mem_header *memHeaderP, -			    CONST char *file, int line, int nukeGuards); +			    const char *file, int line, int nukeGuards);  /*   *---------------------------------------------------------------------- @@ -152,6 +156,10 @@ TclInitDbCkalloc(void)      if (!ckallocInit) {  	ckallocInit = 1;  	ckallocMutexPtr = Tcl_GetAllocMutex(); +#ifndef TCL_THREADS +	/* Silence compiler warning */ +	(void)ckallocMutexPtr; +#endif      }  } @@ -165,22 +173,36 @@ TclInitDbCkalloc(void)   *----------------------------------------------------------------------   */ -void +int  TclDumpMemoryInfo( -    FILE *outFile) +    ClientData clientData, +    int flags)  { -    fprintf(outFile,"total mallocs             %10d\n", -	    total_mallocs); -    fprintf(outFile,"total frees               %10d\n", -	    total_frees); -    fprintf(outFile,"current packets allocated %10d\n", -	    current_malloc_packets); -    fprintf(outFile,"current bytes allocated   %10d\n", -	    current_bytes_malloced); -    fprintf(outFile,"maximum packets allocated %10d\n", -	    maximum_malloc_packets); -    fprintf(outFile,"maximum bytes allocated   %10d\n", -	    maximum_bytes_malloced); +    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;  }  /* @@ -204,7 +226,7 @@ static void  ValidateMemory(      struct mem_header *memHeaderP,  				/* Memory chunk to validate */ -    CONST char *file,		/* File containing the call to +    const char *file,		/* File containing the call to  				 * Tcl_ValidateAllMemory */      int line,			/* Line number of call to  				 * Tcl_ValidateAllMemory */ @@ -228,9 +250,9 @@ ValidateMemory(  	}      }      if (guard_failed) { -	TclDumpMemoryInfo (stderr); +	TclDumpMemoryInfo((ClientData) stderr, 0);  	fprintf(stderr, "low guard failed at %lx, %s %d\n", -		(long unsigned int) memHeaderP->body, file, line); +		(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); @@ -250,9 +272,9 @@ ValidateMemory(      }      if (guard_failed) { -	TclDumpMemoryInfo(stderr); +	TclDumpMemoryInfo((ClientData) stderr, 0);  	fprintf(stderr, "high guard failed at %lx, %s %d\n", -		(long unsigned int) memHeaderP->body, file, line); +		(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, @@ -285,7 +307,7 @@ ValidateMemory(  void  Tcl_ValidateAllMemory( -    CONST char *file,		/* File from which Tcl_ValidateAllMemory was +    const char *file,		/* File from which Tcl_ValidateAllMemory was  				 * called. */      int line)			/* Line number of call to  				 * Tcl_ValidateAllMemory */ @@ -319,7 +341,7 @@ Tcl_ValidateAllMemory(  int  Tcl_DumpActiveMemory( -    CONST char *fileName)	/* Name of the file to write info to */ +    const char *fileName)	/* Name of the file to write info to */  {      FILE *fileP;      struct mem_header *memScanP; @@ -336,10 +358,10 @@ Tcl_DumpActiveMemory(      Tcl_MutexLock(ckallocMutexPtr);      for (memScanP = allocHead; memScanP != NULL; memScanP = memScanP->flink) { -	address = &memScanP->body [0]; +	address = &memScanP->body[0];  	fprintf(fileP, "%8lx - %8lx  %7ld @ %s %d %s", -		(long unsigned int) address, -		(long unsigned int) address + memScanP->length - 1, +		(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); @@ -373,20 +395,23 @@ Tcl_DumpActiveMemory(  char *  Tcl_DbCkalloc(      unsigned int size, -    CONST char *file, +    const char *file,      int line)  { -    struct mem_header *result; +    struct mem_header *result = NULL;      if (validate_memory) {  	Tcl_ValidateAllMemory(file, line);      } -    result = (struct mem_header *) TclpAlloc((unsigned)size + -	    sizeof(struct mem_header) + HIGH_GUARD_SIZE); +    /* 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(stderr); +	TclDumpMemoryInfo((ClientData) stderr, 0);  	Tcl_Panic("unable to alloc %u bytes, %s line %d", size, file, line);      } @@ -440,11 +465,7 @@ Tcl_DbCkalloc(      if (break_on_malloc && (total_mallocs >= break_on_malloc)) {  	break_on_malloc = 0;  	(void) fflush(stdout); -	fprintf(stderr,"reached malloc break limit (%d)\n", -		total_mallocs); -	fprintf(stderr, "program will now enter C debugger\n"); -	(void) fflush(stderr); -	abort(); +	Tcl_Panic("reached malloc break limit (%d)", total_mallocs);      }      current_malloc_packets++; @@ -464,20 +485,23 @@ Tcl_DbCkalloc(  char *  Tcl_AttemptDbCkalloc(      unsigned int size, -    CONST char *file, +    const char *file,      int line)  { -    struct mem_header *result; +    struct mem_header *result = NULL;      if (validate_memory) {  	Tcl_ValidateAllMemory(file, line);      } -    result = (struct mem_header *) TclpAlloc((unsigned)size + -	    sizeof(struct mem_header) + HIGH_GUARD_SIZE); +    /* 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(stderr); +	TclDumpMemoryInfo((ClientData) stderr, 0);  	return NULL;      } @@ -530,11 +554,7 @@ Tcl_AttemptDbCkalloc(      if (break_on_malloc && (total_mallocs >= break_on_malloc)) {  	break_on_malloc = 0;  	(void) fflush(stdout); -	fprintf(stderr,"reached malloc break limit (%d)\n", -		total_mallocs); -	fprintf(stderr, "program will now enter C debugger\n"); -	(void) fflush(stderr); -	abort(); +	Tcl_Panic("reached malloc break limit (%d)", total_mallocs);      }      current_malloc_packets++; @@ -569,16 +589,16 @@ Tcl_AttemptDbCkalloc(   *----------------------------------------------------------------------   */ -int +void  Tcl_DbCkfree(      char *ptr, -    CONST char *file, +    const char *file,      int line)  {      struct mem_header *memp;      if (ptr == NULL) { -	return 0; +	return;      }      /* @@ -589,7 +609,7 @@ Tcl_DbCkfree(       * words on these machines).       */ -    memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET); +    memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET);      if (alloc_tracing) {  	fprintf(stderr, "ckfree %lx %ld %s %d\n", @@ -632,8 +652,6 @@ Tcl_DbCkfree(      }      TclpFree((char *) memp);      Tcl_MutexUnlock(ckallocMutexPtr); - -    return 0;  }  /* @@ -653,7 +671,7 @@ char *  Tcl_DbCkrealloc(      char *ptr,      unsigned int size, -    CONST char *file, +    const char *file,      int line)  {      char *newPtr; @@ -668,7 +686,7 @@ Tcl_DbCkrealloc(       * See comment from Tcl_DbCkfree before you change the following line.       */ -    memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET); +    memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET);      copySize = size;      if (copySize > (unsigned int) memp->length) { @@ -684,7 +702,7 @@ char *  Tcl_AttemptDbCkrealloc(      char *ptr,      unsigned int size, -    CONST char *file, +    const char *file,      int line)  {      char *newPtr; @@ -699,7 +717,7 @@ Tcl_AttemptDbCkrealloc(       * See comment from Tcl_DbCkfree before you change the following line.       */ -    memp = (struct mem_header *) (((unsigned long) ptr) - BODY_OFFSET); +    memp = (struct mem_header *) (((size_t) ptr) - BODY_OFFSET);      copySize = size;      if (copySize > (unsigned int) memp->length) { @@ -732,12 +750,6 @@ Tcl_AttemptDbCkrealloc(   *----------------------------------------------------------------------   */ -#undef Tcl_Alloc -#undef Tcl_Free -#undef Tcl_Realloc -#undef Tcl_AttemptAlloc -#undef Tcl_AttemptRealloc -  char *  Tcl_Alloc(      unsigned int size) @@ -802,32 +814,36 @@ MemoryCmd(      ClientData clientData,      Tcl_Interp *interp,      int argc, -    CONST char *argv[]) +    const char *argv[])  { -    CONST char *fileName; +    const char *fileName; +    FILE *fileP;      Tcl_DString buffer;      int result; +    size_t len;      if (argc < 2) { -	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], -		" option [args..]\"", NULL); +	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 (strcmp(argv[1], "active") == 0 || strcmp(argv[1], "display") == 0) {  	if (argc != 3) { -	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], -		    " ", argv[1], " file\"", NULL); +	    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); +	result = Tcl_DumpActiveMemory(fileName);  	Tcl_DStringFree(&buffer);  	if (result != TCL_OK) { -	    Tcl_AppendResult(interp, "error accessing ", argv[2], NULL); +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf("error accessing %s: %s", +                    argv[2], Tcl_PosixError(interp)));  	    return TCL_ERROR;  	}  	return TCL_OK; @@ -843,25 +859,47 @@ MemoryCmd(      }      if (strcmp(argv[1],"info") == 0) {  	Tcl_SetObjResult(interp, Tcl_ObjPrintf( -		"%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n", +		"%-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", current_bytes_malloced, +		"current bytes allocated", (unsigned long)current_bytes_malloced,  		"maximum packets allocated", maximum_malloc_packets, -		"maximum bytes allocated", maximum_bytes_malloced)); +		"maximum bytes allocated", (unsigned long)maximum_bytes_malloced));  	return TCL_OK;      } -    if (strcmp(argv[1],"init") == 0) { +    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_AppendResult(interp, "wrong # args: should be \"", argv[0], -		    " onexit file\"", NULL); +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                    "wrong # args: should be \"%s onexit file\"", argv[0]));  	    return TCL_ERROR;  	}  	fileName = Tcl_TranslateFileName(interp, argv[2], &buffer); @@ -875,16 +913,17 @@ MemoryCmd(      }      if (strcmp(argv[1],"tag") == 0) {  	if (argc != 3) { -	    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], -		    " tag string\"", NULL); +	    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);  	} -	curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(strlen(argv[2]))); +	len = strlen(argv[2]); +	curTagPtr = (MemTag *) TclpAlloc(TAG_SIZE(len));  	curTagPtr->refCount = 0; -	strcpy(curTagPtr->string, argv[2]); +	memcpy(curTagPtr->string, argv[2], len + 1);  	return TCL_OK;      }      if (strcmp(argv[1],"trace") == 0) { @@ -912,19 +951,20 @@ MemoryCmd(  	return TCL_OK;      } -    Tcl_AppendResult(interp, "bad option \"", argv[1], -	    "\": should be active, break_on_malloc, info, init, onexit, " -	    "tag, trace, trace_on_at_malloc, or validate", NULL); +    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_AppendResult(interp, "wrong # args: should be \"", argv[0], -	    " ", argv[1], " count\"", NULL); +    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +            "wrong # args: should be \"%s %s count\"", argv[0], argv[1]));      return TCL_ERROR;    bad_suboption: -    Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], -	    " ", argv[1], " on|off\"", NULL); +    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +            "wrong # args: should be \"%s %s on|off\"", argv[0], argv[1]));      return TCL_ERROR;  } @@ -951,11 +991,11 @@ CheckmemCmd(      ClientData clientData,	/* Not used. */      Tcl_Interp *interp,		/* Interpreter for evaluation. */      int argc,			/* Number of arguments. */ -    CONST char *argv[])		/* String values of arguments. */ +    const char *argv[])		/* String values of arguments. */  {      if (argc != 2) { -	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], -		" fileName\"", NULL); +	Tcl_SetObjResult(interp, Tcl_ObjPrintf( +                "wrong # args: should be \"%s fileName\"", argv[0]));  	return TCL_ERROR;      }      tclMemDumpFileName = dumpFile; @@ -985,8 +1025,8 @@ Tcl_InitMemory(  				 * added */  {      TclInitDbCkalloc(); -    Tcl_CreateCommand(interp, "memory", MemoryCmd, (ClientData) NULL, NULL); -    Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, (ClientData) 0, NULL); +    Tcl_CreateCommand(interp, "memory", MemoryCmd, NULL, NULL); +    Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, NULL, NULL);  } @@ -1037,7 +1077,7 @@ Tcl_Alloc(  char *  Tcl_DbCkalloc(      unsigned int size, -    CONST char *file, +    const char *file,      int line)  {      char *result; @@ -1075,7 +1115,7 @@ Tcl_AttemptAlloc(  char *  Tcl_AttemptDbCkalloc(      unsigned int size, -    CONST char *file, +    const char *file,      int line)  {      char *result; @@ -1114,7 +1154,7 @@ char *  Tcl_DbCkrealloc(      char *ptr,      unsigned int size, -    CONST char *file, +    const char *file,      int line)  {      char *result; @@ -1154,7 +1194,7 @@ char *  Tcl_AttemptDbCkrealloc(      char *ptr,      unsigned int size, -    CONST char *file, +    const char *file,      int line)  {      char *result; @@ -1182,14 +1222,13 @@ Tcl_Free(      TclpFree(ptr);  } -int +void  Tcl_DbCkfree(      char *ptr, -    CONST char *file, +    const char *file,      int line)  {      TclpFree(ptr); -    return 0;  }  /* @@ -1211,22 +1250,24 @@ Tcl_InitMemory(  int  Tcl_DumpActiveMemory( -    CONST char *fileName) +    const char *fileName)  {      return TCL_OK;  }  void  Tcl_ValidateAllMemory( -    CONST char *file, +    const char *file,      int line)  {  } -void +int  TclDumpMemoryInfo( -    FILE *outFile) +    ClientData clientData, +    int flags)  { +    return 1;  }  #endif	/* TCL_MEM_DEBUG */ @@ -1281,5 +1322,7 @@ TclFinalizeMemorySubsystem(void)   * mode: c   * c-basic-offset: 4   * fill-column: 78 + * tab-width: 8 + * indent-tabs-mode: nil   * End:   */ | 
