From f6514cb20593a23726967be44adf8f2176e18185 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 3 Oct 2003 20:31:23 +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/tclCmdMZ.c | 81 +++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 75 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index b435ddc..798c208 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-03 Vince Darley * tests/fileName.test: diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 50f80d4..dc4fe90 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.75.2.6 2003/09/29 22:03:44 dgp Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.75.2.7 2003/10/03 20:31:23 dgp Exp $ */ #include "tclInt.h" @@ -2550,11 +2550,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/tclCmdMZ.c b/generic/tclCmdMZ.c index a3dc03a..eac4bda 100644 --- a/generic/tclCmdMZ.c +++ b/generic/tclCmdMZ.c @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCmdMZ.c,v 1.82.2.7 2003/09/24 02:17:10 dgp Exp $ + * RCS: @(#) $Id: tclCmdMZ.c,v 1.82.2.8 2003/10/03 20:31:24 dgp Exp $ */ #include "tclInt.h" @@ -3257,8 +3257,10 @@ 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)) { - flags |= (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); + 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); name = Tcl_GetString(objv[3]); @@ -3299,8 +3301,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); } @@ -3321,7 +3323,11 @@ TclTraceExecutionObjCmd(interp, optionIndex, objc, objv) /* Postpone deletion */ tcmdPtr->flags = 0; } - if ((--tcmdPtr->refCount) <= 0) { + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TclTraceExecutionObjCmd: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } break; @@ -3524,7 +3530,11 @@ TclTraceCommandObjCmd(interp, optionIndex, objc, objv) flags | TCL_TRACE_DELETE, TraceCommandProc, clientData); tcmdPtr->flags |= TCL_TRACE_DESTROYED; - if ((--tcmdPtr->refCount) <= 0) { + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TclTraceCommandObjCmd: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { ckfree((char *) tcmdPtr); } break; @@ -4096,6 +4106,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; @@ -4107,13 +4119,38 @@ TraceCommandProc(clientData, interp, oldName, newName, flags) /* Postpone deletion, until exec trace returns */ tcmdPtr->flags = 0; } + + /* + * 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; + } + /* - * Decrement the refCount since the command which held our - * reference (ever since we were created) has just gone away + * 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) { + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TraceCommandProc: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } return; @@ -4197,7 +4234,11 @@ TclCheckExecutionTraces(interp, command, numChars, cmdPtr, code, tcmdPtr->refCount++; traceCode = TraceExecutionProc((ClientData)tcmdPtr, interp, curLevel, command, (Tcl_Command)cmdPtr, objc, objv); - if ((--tcmdPtr->refCount) <= 0) { + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TclCheckExecutionTraces: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } } @@ -4404,8 +4445,12 @@ CallTraceProcedure(interp, tracePtr, cmdPtr, command, numChars, objc, objv) static void CommandObjTraceDeleted(ClientData clientData) { TraceCommandInfo* tcmdPtr = (TraceCommandInfo*)clientData; - if ((--tcmdPtr->refCount) <= 0) { - ckfree((char*)tcmdPtr); + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("CommandObjTraceDeleted: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { + ckfree((char*)tcmdPtr); } } @@ -4464,8 +4509,8 @@ TraceExecutionProc(ClientData clientData, Tcl_Interp *interp, * operations, but with either of the step operations. */ if (flags & TCL_TRACE_EXEC_DIRECT) { - call = flags & tcmdPtr->flags & (TCL_TRACE_ENTER_EXEC | - TCL_TRACE_LEAVE_EXEC); + call = flags & tcmdPtr->flags + & (TCL_TRACE_ENTER_EXEC | TCL_TRACE_LEAVE_EXEC); } else { call = 1; } @@ -4605,7 +4650,11 @@ TraceExecutionProc(ClientData clientData, Tcl_Interp *interp, } } if (call) { - if ((--tcmdPtr->refCount) <= 0) { + tcmdPtr->refCount--; + if (tcmdPtr->refCount < 0) { + Tcl_Panic("TraceExecutionProc: negative TraceCommandInfo refCount"); + } + if (tcmdPtr->refCount == 0) { ckfree((char*)tcmdPtr); } } -- cgit v0.12