summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--generic/tclBasic.c10
-rw-r--r--generic/tclTrace.c35
3 files changed, 38 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index d50dcc5..eeaa820 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2003-10-03 Don Porter <dgp@users.sourceforge.net>
+
+ * generic/tclBasic.c: Fixed error in ref count management of command
+ * generic/tclCmdMZ.c: and execution traces that caused access to
+ freed memory in trace-32.1. [Bug 811483].
+
2003-10-02 Don Porter <dgp@users.sourceforge.net>
* generic/tclTrace.c: Corrected comingling of introspection results of
diff --git a/generic/tclBasic.c b/generic/tclBasic.c
index 2447818..4ef3285 100644
--- a/generic/tclBasic.c
+++ b/generic/tclBasic.c
@@ -13,7 +13,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclBasic.c,v 1.89 2003/09/29 23:56:15 dkf Exp $
+ * RCS: @(#) $Id: tclBasic.c,v 1.90 2003/10/03 20:42:06 dgp Exp $
*/
#include "tclInt.h"
@@ -2611,11 +2611,9 @@ CallCommandTraces(iPtr, cmdPtr, oldName, newName, flags)
* must get the name from cmdPtr */
CONST char *newName; /* Command's new name, or NULL if
* the command is not being renamed */
- int flags; /* Flags passed to trace procedures:
- * indicates what's happening to command,
- * plus other stuff like TCL_GLOBAL_ONLY,
- * TCL_NAMESPACE_ONLY, and
- * TCL_INTERP_DESTROYED. */
+ int flags; /* Flags indicating the type of traces
+ * to trigger, either TCL_TRACE_DELETE
+ * or TCL_TRACE_RENAME. */
{
register CommandTrace *tracePtr;
ActiveCommandTrace active;
diff --git a/generic/tclTrace.c b/generic/tclTrace.c
index be49d7b..df04703 100644
--- a/generic/tclTrace.c
+++ b/generic/tclTrace.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclTrace.c,v 1.5 2003/10/02 18:08:31 dgp Exp $
+ * RCS: @(#) $Id: tclTrace.c,v 1.6 2003/10/03 20:42:06 dgp Exp $
*/
#include "tclInt.h"
@@ -506,7 +506,8 @@ TclTraceExecutionObjCmd(interp, optionIndex, objc, objv)
tcmdPtr->length = length;
tcmdPtr->refCount = 1;
flags |= TCL_TRACE_DELETE;
- if (flags & (TRACE_EXEC_ENTER_STEP | TRACE_EXEC_LEAVE_STEP)) {
+ if (flags & (TCL_TRACE_ENTER_DURING_EXEC |
+ TCL_TRACE_LEAVE_DURING_EXEC)) {
flags |= (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC);
}
strcpy(tcmdPtr->command, command);
@@ -548,8 +549,8 @@ TclTraceExecutionObjCmd(interp, optionIndex, objc, objv)
&& (strncmp(command, tcmdPtr->command,
(size_t) length) == 0)) {
flags |= TCL_TRACE_DELETE;
- if (flags & (TRACE_EXEC_ENTER_STEP |
- TRACE_EXEC_LEAVE_STEP)) {
+ if (flags & (TCL_TRACE_ENTER_DURING_EXEC |
+ TCL_TRACE_LEAVE_DURING_EXEC)) {
flags |= (TCL_TRACE_ENTER_EXEC |
TCL_TRACE_LEAVE_EXEC);
}
@@ -1351,6 +1352,8 @@ TraceCommandProc(clientData, interp, oldName, newName, flags)
* because command deletes are unconditional, so the trace must go away.
*/
if (flags & (TCL_TRACE_DESTROYED | TCL_TRACE_DELETE)) {
+ int untraceFlags = tcmdPtr->flags;
+
if (tcmdPtr->stepTrace != NULL) {
Tcl_DeleteTrace(interp, tcmdPtr->stepTrace);
tcmdPtr->stepTrace = NULL;
@@ -1362,10 +1365,28 @@ TraceCommandProc(clientData, interp, oldName, newName, flags)
/* Postpone deletion, until exec trace returns */
tcmdPtr->flags = 0;
}
- /*
- * Decrement the refCount since the command which held our
- * reference (ever since we were created) has just gone away
+ /*
+ * We need to construct the same flags for Tcl_UntraceCommand
+ * as were passed to Tcl_TraceCommand. Reproduce the processing
+ * of [trace add execution/command]. Be careful to keep this
+ * code in sync with that.
+ */
+ if (untraceFlags & TCL_TRACE_ANY_EXEC) {
+ untraceFlags |= TCL_TRACE_DELETE;
+ if (untraceFlags & (TCL_TRACE_ENTER_DURING_EXEC
+ | TCL_TRACE_LEAVE_DURING_EXEC)) {
+ untraceFlags |= (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC);
+ }
+ } else if (untraceFlags & TCL_TRACE_RENAME) {
+ untraceFlags |= TCL_TRACE_DELETE;
+ }
+ /*
+ * Remove the trace since TCL_TRACE_DESTROYED tells us to, or the
+ * command we're tracing has just gone away. Then decrement the
+ * clientData refCount that was set up by trace creation.
*/
+ Tcl_UntraceCommand(interp, oldName, untraceFlags,
+ TraceCommandProc, clientData);
tcmdPtr->refCount--;
}
if ((--tcmdPtr->refCount) <= 0) {