Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.769
diff -u -u -r1.769 ChangeLog
--- ChangeLog	2001/12/27 22:46:12	1.769
+++ ChangeLog	2001/12/28 23:32:21
@@ -1,3 +1,23 @@
+2001-12-29  Don Porter <dgp@users.sourceforge.net>
+
+	* generic/tclCkalloc.c (MemoryCmd, TclFinalizeMemorySubsystem):
+	Added the [memory onexit] command, intended to replace [checkmem].
+
+	* doc/DumpActiveMemory.3: 
+	* doc/memory.n: Updated documentation for [memory] and related
+	matters.  [Bug 487677]
+
+	* mac/tclMacBOAMain.c (Tcl_Main, CheckmemCmd): Removed all the
+	machinery for the [checkmem] command that is completely duplicated
+	by code in generic/tclCkalloc.c.
+
+	* generic/tclBinary.c:
+	* generic/tclListObj.c:
+	* generic/tclObj.c:
+	* generic/tclStringObj.c: Removed references to [checkmem] in
+	comments, referencing [memory active] instead, since it is
+	documented.
+
 2001-12-28  Daniel Steffen <das@users.sourceforge.net>
 
 	* mac/tclMacInit.c:
@@ -103,7 +123,6 @@
 	* doc/CrtInterp.3:
 	* generic/tclBasic.c: docs and comments corrections [Bug 493412]
 	Bug & patch by Don Porter.  
-	
 
 2001-12-14  Donal K. Fellows  <fellowsd@cs.man.ac.uk>
 
Index: doc/DumpActiveMemory.3
===================================================================
RCS file: /cvsroot/tcl/tcl/doc/DumpActiveMemory.3,v
retrieving revision 1.4
diff -u -u -r1.4 DumpActiveMemory.3
--- doc/DumpActiveMemory.3	2001/05/03 23:52:56	1.4
+++ doc/DumpActiveMemory.3	2001/12/28 23:32:21
@@ -37,8 +37,9 @@
 
 .SH DESCRIPTION
 These functions provide access to Tcl memory debugging information.
-They are only available when Tcl has been compiled with
-\fBTCL_MEM_DEBUG\fR defined at compile-time.
+They are only functional when Tcl has been compiled with
+\fBTCL_MEM_DEBUG\fR defined at compile-time.  When \fBTCL_MEM_DEBUG\fR
+is not defined, these functions are all no-ops.
 .PP 
 \fBTcl_DumpActiveMemory\fR will output a list of all currently
 allocated memory to the specified file.  The information output for
@@ -49,8 +50,8 @@
 interpreter has been deleted.
 .PP
 \fBTcl_InitMemory\fR adds the Tcl \fBmemory\fR command to the
-interpreter given by \fIinterp\fR.  It is called by \fBTcl_Main\fR
-when Tcl has been compiled with \fBTCL_MEM_DEBUG\fR defined.
+interpreter given by \fIinterp\fR.  \fBTcl_InitMemory\fR is called
+by \fBTcl_Main\fR.
 .PP
 \fBTcl_ValidateAllMemory\fR forces a validation of the guard zones of
 all currently allocated blocks of memory.  Normally validation of a
Index: doc/memory.n
===================================================================
RCS file: /cvsroot/tcl/tcl/doc/memory.n,v
retrieving revision 1.3
diff -u -u -r1.3 memory.n
--- doc/memory.n	2000/09/07 14:27:49	1.3
+++ doc/memory.n	2001/12/28 23:32:22
@@ -19,15 +19,42 @@
 debugging capabilities.  The memory command has several suboptions, which are
 described below.  It is only available when Tcl has been compiled with
 memory debugging enabled (when \fBTCL_MEM_DEBUG\fR is defined at
-compile time).
+compile time), and after \fBTcl_InitMemory\fR has been called.
 .TP
+\fBmemory active\fR \fIfile\fR
+Write a list of all currently allocated memory to the specified \fIfile\fR.
+.TP
+\fBmemory break_on_malloc\fR \fIcount\fR
+After the \fIcount\fR allocations have been performed, \fBckalloc\fR
+outputs a message to this effect and that it is now attempting to enter
+the C debugger.  Tcl will then issue a \fISIGINT\fR signal against itself.
+If you are running Tcl under a C debugger, it should then enter the debugger
+command mode.
+.TP
 \fBmemory info\fR
-Produces a report containing the total allocations and frees since 
+Returns a report containing the total allocations and frees since 
 Tcl began, the current packets allocated (the current
 number of calls to \fBckalloc\fR not met by a corresponding call 
 to \fBckfree\fR), the current bytes allocated, and the maximum number
 of packets and bytes allocated.
 .TP
+\fB memory init [on|off]\fR
+Turn on or off the pre-initialization of all allocated memory
+with bogus bytes.  Useful for detecting the use of uninitialized values.
+.TP
+\fBmemory onexit\fR \fIfile\fR
+Causes a list of all allocated memory to be written to the specified \fIfile\fR
+during the finalization of Tcl's memory subsystem.  Useful for checking
+that memory is properly cleaned up during process exit.
+.TP
+\fBmemory tag\fR \fIstring\fR
+Each packet of memory allocated by \fBckalloc\fR can have associated
+with it a string-valued tag.  In the lists of allocated memory generated
+by \fBmemory active\fR and \fBmemory onexit\fR, the tag for each packet
+is printed along with other information about the packet.  The
+\fBmemory tag\fR command sets the tag value for subsequent calls
+to \fBckalloc\fR to be \fIstring\fR.  
+.TP
 \fBmemory trace [on|off]\fR
 .br
 Turns memory tracing on or off.  When memory tracing is on, every call
@@ -35,23 +62,13 @@
 \fIstderr\fR, consisting of the word \fIckalloc\fR, followed by the
 address returned, the amount of memory allocated, and the C filename
 and line number of the code performing the allocation.  For example:
+.RS
 .CS
 ckalloc 40e478 98 tclProc.c 1406
 .CE
 Calls to \fBckfree\fR are traced in the same manner.
+.RE
 .TP
-\fBmemory validate [on|off]\fR
-Turns memory validation on or off. When memory validation is enabled,
-on every call to \fBckalloc\fR or \fBckfree\fR, the guard zones are
-checked for every piece of memory currently in existence that was
-allocated by \fBckalloc\fR.  This has a large performance impact and
-should only be used when overwrite problems are strongly suspected.
-The advantage of enabling memory validation is that a guard zone
-overwrite can be detected on the first call to \fBckalloc\fR or
-\fBckfree\fR after the overwrite occurred, rather than when the
-specific memory with the overwritten guard zone(s) is freed, which may
-occur long after the overwrite occurred.
-.TP
 \fBmemory trace_on_at_malloc\fR \fIcount\fR
 Enable memory tracing after \fIcount\fR \fBckalloc\fR's have been performed.
 For example, if you enter \fBmemory trace_on_at_malloc 100\fR,
@@ -63,15 +80,17 @@
 the problem sets in.  The current number of memory allocations that have 
 occurred since Tcl started is printed on a guard zone failure.
 .TP
-\fBmemory break_on_malloc\fR \fIcount\fR
-After the \fBcount\fR allocations have been performed, \fBckalloc\fR's
-output a message to this effect and that it is now attempting to enter
-the C debugger.  Tcl will then issue a \fISIGINT\fR signal against itself.
-If you are running Tcl under a C debugger, it should then enter the debugger
-command mode.
-.TP
-\fB memory display\fR \fIfile\fR
-Write a list of all currently allocated memory to the specified file.
+\fBmemory validate [on|off]\fR
+Turns memory validation on or off. When memory validation is enabled,
+on every call to \fBckalloc\fR or \fBckfree\fR, the guard zones are
+checked for every piece of memory currently in existence that was
+allocated by \fBckalloc\fR.  This has a large performance impact and
+should only be used when overwrite problems are strongly suspected.
+The advantage of enabling memory validation is that a guard zone
+overwrite can be detected on the first call to \fBckalloc\fR or
+\fBckfree\fR after the overwrite occurred, rather than when the
+specific memory with the overwritten guard zone(s) is freed, which may
+occur long after the overwrite occurred.
 
 .SH "SEE ALSO"
 ckalloc, ckfree, Tcl_ValidateAllMemory, Tcl_DumpActiveMemory, TCL_MEM_DEBUG
Index: generic/tclBinary.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclBinary.c,v
retrieving revision 1.9
diff -u -u -r1.9 tclBinary.c
--- generic/tclBinary.c	2001/11/29 15:38:40	1.9
+++ generic/tclBinary.c	2001/12/28 23:32:22
@@ -180,8 +180,8 @@
  *	TCL_MEM_DEBUG is defined. It is the same as the Tcl_NewByteArrayObj
  *	above except that it calls Tcl_DbCkalloc directly with the file name
  *	and line number from its caller. This simplifies debugging since then
- *	the checkmem command will report the correct file name and line number
- *	when reporting objects that haven't been freed.
+ *	the [memory active] command will report the correct file name and line
+ *	number when reporting objects that haven't been freed.
  *
  *	When TCL_MEM_DEBUG is not defined, this procedure just returns the
  *	result of calling Tcl_NewByteArrayObj.
Index: generic/tclCkalloc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclCkalloc.c,v
retrieving revision 1.13
diff -u -u -r1.13 tclCkalloc.c
--- generic/tclCkalloc.c	2001/12/18 15:21:20	1.13
+++ generic/tclCkalloc.c	2001/12/28 23:32:22
@@ -111,6 +111,7 @@
 
 char *tclMemDumpFileName = NULL;
 
+static char *onExitMemDumpFileName = NULL;
 static char dumpFile[100];	/* Records where to dump memory allocation
 				 * information. */
 
@@ -304,7 +305,7 @@
  *	information will be written to stderr.
  *
  * Results:
- *	Return TCL_ERROR if an error accessing the file occures, `errno' 
+ *	Return TCL_ERROR if an error accessing the file occurs, `errno' 
  *	will have the file error number left in it.
  *----------------------------------------------------------------------
  */
@@ -759,11 +760,14 @@
  * 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 display
- *		memory break_on_malloc count
- *		memory trace_on_at_malloc count
+ *		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:
@@ -789,10 +793,10 @@
 	return TCL_ERROR;
     }
 
-    if (strcmp(argv[1],"active") == 0) {
+    if ((strcmp(argv[1],"active") == 0) || (strcmp(argv[1],"display") == 0)) {
         if (argc != 3) {
 	    Tcl_AppendResult(interp, "wrong # args: should be \"",
-		    argv[0], " active file\"", (char *) NULL);
+		    argv[0], " ", argv[1], " file\"", (char *) NULL);
 	    return TCL_ERROR;
 	}
 	fileName = Tcl_TranslateFileName(interp, argv[2], &buffer);
@@ -818,14 +822,14 @@
         return TCL_OK;
     }
     if (strcmp(argv[1],"info") == 0) {
-	char buffer[400];
-	sprintf(buffer, "%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n",
+	char buf[400];
+	sprintf(buf, "%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n%-25s %10d\n",
 	    "total mallocs", total_mallocs, "total frees", total_frees,
 	    "current packets allocated", current_malloc_packets,
 	    "current bytes allocated", current_bytes_malloced,
 	    "maximum packets allocated", maximum_malloc_packets,
 	    "maximum bytes allocated", maximum_bytes_malloced);
-	Tcl_SetResult(interp, buffer, TCL_VOLATILE);
+	Tcl_SetResult(interp, buf, TCL_VOLATILE);
         return TCL_OK;
     }
     if (strcmp(argv[1],"init") == 0) {
@@ -835,6 +839,21 @@
         init_malloced_bodies = (strcmp(argv[2],"on") == 0);
         return TCL_OK;
     }
+    if (strcmp(argv[1],"onexit") == 0) {
+        if (argc != 3) {
+	    Tcl_AppendResult(interp, "wrong # args: should be \"",
+		    argv[0], " onexit file\"", (char *) NULL);
+	    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_AppendResult(interp, "wrong # args: should be \"", argv[0],
@@ -875,7 +894,7 @@
     }
 
     Tcl_AppendResult(interp, "bad option \"", argv[1],
-	    "\": should be active, break_on_malloc, info, init, ",
+	    "\": should be active, break_on_malloc, info, init, onexit, ",
 	    "tag, trace, trace_on_at_malloc, or validate", (char *) NULL);
     return TCL_ERROR;
 
@@ -1216,6 +1235,8 @@
     Tcl_MutexLock(ckallocMutexPtr);
     if (tclMemDumpFileName != NULL) {
 	Tcl_DumpActiveMemory(tclMemDumpFileName);
+    } else if (onExitMemDumpFileName != NULL) {
+	Tcl_DumpActiveMemory(onExitMemDumpFileName);
     }
     if (curTagPtr != NULL) {
 	TclpFree((char *) curTagPtr);
Index: generic/tclListObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclListObj.c,v
retrieving revision 1.11
diff -u -u -r1.11 tclListObj.c
--- generic/tclListObj.c	2001/11/16 21:41:14	1.11
+++ generic/tclListObj.c	2001/12/28 23:32:22
@@ -132,9 +132,9 @@
  *	TCL_MEM_DEBUG is defined. It creates new list objects. It is the
  *	same as the Tcl_NewListObj procedure above except that it calls
  *	Tcl_DbCkalloc directly with the file name and line number from its
- *	caller. This simplifies debugging since then the checkmem command
- *	will report the correct file name and line number when reporting
- *	objects that haven't been freed.
+ *	caller. This simplifies debugging since then the [memory active]
+ *	command	will report the correct file name and line number when
+ *	reporting objects that haven't been freed.
  *
  *	When TCL_MEM_DEBUG is not defined, this procedure just returns the
  *	result of calling Tcl_NewListObj.
Index: generic/tclObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclObj.c,v
retrieving revision 1.26
diff -u -u -r1.26 tclObj.c
--- generic/tclObj.c	2001/11/23 01:28:58	1.26
+++ generic/tclObj.c	2001/12/28 23:32:22
@@ -534,7 +534,7 @@
  *	empty string. It is the same as the Tcl_NewObj procedure above
  *	except that it calls Tcl_DbCkalloc directly with the file name and
  *	line number from its caller. This simplifies debugging since then
- *	the checkmem command will report the correct file name and line
+ *	the [memory active] command will report the correct file name and line
  *	number when reporting objects that haven't been freed.
  *
  *	When TCL_MEM_DEBUG is not defined, this procedure just returns the
@@ -936,9 +936,9 @@
  *	TCL_MEM_DEBUG is defined. It creates new boolean objects. It is the
  *	same as the Tcl_NewBooleanObj procedure above except that it calls
  *	Tcl_DbCkalloc directly with the file name and line number from its
- *	caller. This simplifies debugging since then the checkmem command
- *	will report the correct file name and line number when reporting
- *	objects that haven't been freed.
+ *	caller. This simplifies debugging since then the [memory active]
+ *	command	will report the correct file name and line number when
+ *	reporting objects that haven't been freed.
  *
  *	When TCL_MEM_DEBUG is not defined, this procedure just returns the
  *	result of calling Tcl_NewBooleanObj.
@@ -1294,9 +1294,9 @@
  *	TCL_MEM_DEBUG is defined. It creates new double objects. It is the
  *	same as the Tcl_NewDoubleObj procedure above except that it calls
  *	Tcl_DbCkalloc directly with the file name and line number from its
- *	caller. This simplifies debugging since then the checkmem command
- *	will report the correct file name and line number when reporting
- *	objects that haven't been freed.
+ *	caller. This simplifies debugging since then the [memory active]
+ *	command	will report the correct file name and line number when
+ *	reporting objects that haven't been freed.
  *
  *	When TCL_MEM_DEBUG is not defined, this procedure just returns the
  *	result of calling Tcl_NewDoubleObj.
@@ -1925,8 +1925,8 @@
  *	When the core is compiled with TCL_MEM_DEBUG defined,
  *	Tcl_DbNewLongObj calls Tcl_DbCkalloc directly with the file name and
  *	line number from its caller. This simplifies debugging since then
- *	the checkmem command will report the caller's file name and line
- *	number when reporting objects that haven't been freed.
+ *	the [memory active] command will report the caller's file name and
+ *	line number when reporting objects that haven't been freed.
  *
  *	Otherwise, when the core is compiled without TCL_MEM_DEBUG defined,
  *	this procedure just returns the result of calling Tcl_NewLongObj.
Index: generic/tclStringObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclStringObj.c,v
retrieving revision 1.21
diff -u -u -r1.21 tclStringObj.c
--- generic/tclStringObj.c	2001/05/15 21:30:46	1.21
+++ generic/tclStringObj.c	2001/12/28 23:32:23
@@ -219,9 +219,9 @@
  *	TCL_MEM_DEBUG is defined. It creates new string objects. It is the
  *	same as the Tcl_NewStringObj procedure above except that it calls
  *	Tcl_DbCkalloc directly with the file name and line number from its
- *	caller. This simplifies debugging since then the checkmem command
- *	will report the correct file name and line number when reporting
- *	objects that haven't been freed.
+ *	caller. This simplifies debugging since then the [memory active]
+ *	command	will report the correct file name and line number when
+ *	reporting objects that haven't been freed.
  *
  *	When TCL_MEM_DEBUG is not defined, this procedure just returns the
  *	result of calling Tcl_NewStringObj.
Index: mac/tclMacBOAMain.c
===================================================================
RCS file: /cvsroot/tcl/tcl/mac/tclMacBOAMain.c,v
retrieving revision 1.3
diff -u -u -r1.3 tclMacBOAMain.c
--- mac/tclMacBOAMain.c	1999/04/16 00:47:19	1.3
+++ mac/tclMacBOAMain.c	2001/12/28 23:32:23
@@ -49,22 +49,10 @@
 
 static Tcl_Interp *interp;	/* Interpreter for application. */
 
-#ifdef TCL_MEM_DEBUG
-static char dumpFile[100];	/* Records where to dump memory allocation
-				 * information. */
-static int quitFlag = 0;	/* 1 means "checkmem" command was called,
-				 * so the application should quit and dump
-				 * memory allocation information. */
-#endif
-
 /*
  * Forward references for procedures defined later in this file:
  */
 
-#ifdef TCL_MEM_DEBUG
-static int		CheckmemCmd _ANSI_ARGS_((ClientData clientData,
-			    Tcl_Interp *interp, int argc, char *argv[]));
-#endif
 void TclMacDoNotification(char *mssg);
 void TclMacNotificationResponse(NMRecPtr nmRec); 
 int Tcl_MacBGNotifyObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv);
@@ -108,11 +96,7 @@
 
     Tcl_FindExecutable(argv[0]);
     interp = Tcl_CreateInterp();
-#ifdef TCL_MEM_DEBUG
     Tcl_InitMemory(interp);
-    Tcl_CreateCommand(interp, "checkmem", CheckmemCmd, (ClientData) 0,
-	    (Tcl_CmdDeleteProc *) NULL);
-#endif
 
     /*
      * Make command-line arguments available in the Tcl variables "argc"
@@ -318,44 +302,3 @@
            
 }
 
-
-/*
- *----------------------------------------------------------------------
- *
- * 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.
- *
- *----------------------------------------------------------------------
- */
-#ifdef TCL_MEM_DEBUG
-
-	/* ARGSUSED */
-static int
-CheckmemCmd(clientData, interp, argc, argv)
-    ClientData clientData;		/* Not used. */
-    Tcl_Interp *interp;			/* Interpreter for evaluation. */
-    int argc;				/* Number of arguments. */
-    char *argv[];			/* String values of arguments. */
-{
-    extern char *tclMemDumpFileName;
-    if (argc != 2) {
-	Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
-		" fileName\"", (char *) NULL);
-	return TCL_ERROR;
-    }
-    strcpy(dumpFile, argv[1]);
-    tclMemDumpFileName = dumpFile;
-    quitFlag = 1;
-    return TCL_OK;
-}
-#endif
