diff options
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | generic/tclBasic.c | 29 | ||||
-rw-r--r-- | tests/trace.test | 20 |
3 files changed, 46 insertions, 13 deletions
@@ -1,3 +1,13 @@ +2006-11-03 Miguel Sofer <msofer@users.sf.net> + + * generic/tclBasic.c (TEOVI): fix por possible leak of a Command + in the presence of execution traces that delete it. + + * generic/tclBasic.c (TEOVI): + * tests/trace.test (trace-21.11): fix for [Bug 1590232], execution + traces may cause a second command resolution in the wrong + namespace. + 2006-11-01 Daniel Steffen <das@users.sourceforge.net> * generic/tclEnv.c (Darwin): mark _environ symbol as unexported. diff --git a/generic/tclBasic.c b/generic/tclBasic.c index 9807a19..f55c531 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.24 2006/09/25 17:27:31 andreas_kupries Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.75.2.25 2006/11/04 01:37:55 msofer Exp $ */ #include "tclInt.h" @@ -3008,21 +3008,23 @@ TclEvalObjvInternal(interp, objc, objv, command, length, flags) return TCL_OK; } - /* Configure evaluation context to match the requested flags */ - savedVarFramePtr = iPtr->varFramePtr; - if (flags & TCL_EVAL_GLOBAL) { - iPtr->varFramePtr = NULL; - } else if ((flags & TCL_EVAL_INVOKE) && iPtr->varFramePtr) { - savedNsPtr = iPtr->varFramePtr->nsPtr; - iPtr->varFramePtr->nsPtr = iPtr->globalNsPtr; - } /* * If any execution traces rename or delete the current command, * we may need (at most) two passes here. */ + + savedVarFramePtr = iPtr->varFramePtr; while (1) { + /* Configure evaluation context to match the requested flags */ + if (flags & TCL_EVAL_GLOBAL) { + iPtr->varFramePtr = NULL; + } else if ((flags & TCL_EVAL_INVOKE) && iPtr->varFramePtr) { + savedNsPtr = iPtr->varFramePtr->nsPtr; + iPtr->varFramePtr->nsPtr = iPtr->globalNsPtr; + } + /* * Find the procedure to execute this command. If there isn't one, * then see if there is a command "unknown". If so, create a new @@ -3067,7 +3069,9 @@ TclEvalObjvInternal(interp, objc, objv, command, length, flags) */ if ((checkTraces) && (command != NULL)) { int cmdEpoch = cmdPtr->cmdEpoch; - cmdPtr->refCount++; + int newEpoch; + + cmdPtr->refCount++; /* * If the first set of traces modifies/deletes the command or * any existing traces, then the set checkTraces to 0 and @@ -3082,8 +3086,9 @@ TclEvalObjvInternal(interp, objc, objv, command, length, flags) traceCode = TclCheckExecutionTraces(interp, command, length, cmdPtr, code, TCL_TRACE_ENTER_EXEC, objc, objv); } - cmdPtr->refCount--; - if (cmdEpoch != cmdPtr->cmdEpoch) { + newEpoch = cmdPtr->cmdEpoch; + TclCleanupCommand(cmdPtr); + if (cmdEpoch != newEpoch) { /* The command has been modified in some way */ checkTraces = 0; continue; diff --git a/tests/trace.test b/tests/trace.test index a85bda2..32e1b4e 100644 --- a/tests/trace.test +++ b/tests/trace.test @@ -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: trace.test,v 1.26.2.16 2006/04/11 14:37:05 dgp Exp $ +# RCS: @(#) $Id: trace.test,v 1.26.2.17 2006/11/04 01:37:56 msofer Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest @@ -1624,6 +1624,24 @@ test trace-21.10 {trace execution: TCL_EVAL_GLOBAL} testevalobjv { set ::info } {SUCCESS 1 SUCCESS 1} +test trace-21.11 {trace execution and alias} -setup { + set res {} + proc ::x {} {return ::} + namespace eval a {} + proc ::a::x {} {return ::a} + interp alias {} y {} x +} -body { + lappend res [namespace eval ::a y] + trace add execution ::x enter { + rename ::x {} + proc ::x {} {return ::} + #} + lappend res [namespace eval ::a y] +} -cleanup { + namespace delete a + rename ::x {} +} -result {:: ::} + proc factorial {n} { if {$n != 1} { return [expr {$n * [factorial [expr {$n -1 }]]}] } return 1 |