From 5a7659af1087fa2c7e87967ad997b2364e8f1295 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 3 Oct 2003 20:42:06 +0000 Subject: * 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]. --- ChangeLog | 6 ++++++ generic/tclBasic.c | 10 ++++------ generic/tclTrace.c | 35 ++++++++++++++++++++++++++++------- 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 + + * 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 * 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) { -- cgit v0.12