From fc743498e7623e7cefbe124ef936d30de91e3625 Mon Sep 17 00:00:00 2001 From: dgp Date: Wed, 7 Sep 2016 18:31:58 +0000 Subject: Attempt to fix [7f02ff1efa]. Make trace-18.1 fail. Suspect test is an experiment that preserves the bug. --- generic/tclNamesp.c | 20 +++++++------------- generic/tclVar.c | 49 +++++++++++++++++++++++++++++++++---------------- 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index 7f6ecf5..74dfaf8 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -382,19 +382,6 @@ Tcl_PopCallFrame( register CallFrame *framePtr = iPtr->framePtr; Namespace *nsPtr; - /* - * It's important to remove the call frame from the interpreter's stack of - * call frames before deleting local variables, so that traces invoked by - * the variable deletion don't see the partially-deleted frame. - */ - - if (framePtr->callerPtr) { - iPtr->framePtr = framePtr->callerPtr; - iPtr->varFramePtr = framePtr->callerVarPtr; - } else { - /* Tcl_PopCallFrame: trying to pop rootCallFrame! */ - } - if (framePtr->varTablePtr != NULL) { TclDeleteVars(iPtr, framePtr->varTablePtr); ckfree(framePtr->varTablePtr); @@ -422,6 +409,13 @@ Tcl_PopCallFrame( } framePtr->nsPtr = NULL; + if (framePtr->callerPtr) { + iPtr->framePtr = framePtr->callerPtr; + iPtr->varFramePtr = framePtr->callerVarPtr; + } else { + /* Tcl_PopCallFrame: trying to pop rootCallFrame! */ + } + if (framePtr->tailcallPtr) { TclSetTailcall(interp, framePtr->tailcallPtr); } diff --git a/generic/tclVar.c b/generic/tclVar.c index 48e09f6..0b371ee 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -5032,27 +5032,44 @@ TclDeleteVars( TclVarHashTable *tablePtr) /* Hash table containing variables to * delete. */ { - Tcl_Interp *interp = (Tcl_Interp *) iPtr; Tcl_HashSearch search; register Var *varPtr; - int flags; - Namespace *currNsPtr = (Namespace *) TclGetCurrentNamespace(interp); - - /* - * Determine what flags to pass to the trace callback functions. - */ - - flags = TCL_TRACE_UNSETS; - if (tablePtr == &iPtr->globalNsPtr->varTable) { - flags |= TCL_GLOBAL_ONLY; - } else if (tablePtr == &currNsPtr->varTable) { - flags |= TCL_NAMESPACE_ONLY; - } for (varPtr = VarHashFirstVar(tablePtr, &search); varPtr != NULL; varPtr = VarHashFirstVar(tablePtr, &search)) { - UnsetVarStruct(varPtr, NULL, iPtr, VarHashGetKey(varPtr), NULL, flags, - -1); + VarHashRefCount(varPtr)++; + + UnsetVarStruct(varPtr, NULL, iPtr, VarHashGetKey(varPtr), + NULL, TCL_TRACE_UNSETS, -1); + + if (TclIsVarTraced(varPtr)) { + Tcl_HashEntry *tPtr = Tcl_FindHashEntry(&iPtr->varTraces, varPtr); + VarTrace *tracePtr = Tcl_GetHashValue(tPtr); + ActiveVarTrace *activePtr; + + while (tracePtr) { + VarTrace *prevPtr = tracePtr; + + tracePtr = tracePtr->nextPtr; + prevPtr->nextPtr = NULL; + Tcl_EventuallyFree(prevPtr, TCL_DYNAMIC); + } + Tcl_DeleteHashEntry(tPtr); + varPtr->flags &= ~VAR_ALL_TRACES; + for (activePtr = iPtr->activeVarTracePtr; activePtr != NULL; + activePtr = activePtr->nextPtr) { + if (activePtr->varPtr == varPtr) { + activePtr->nextTracePtr = NULL; + } + } + } + + if (!TclIsVarUndefined(varPtr)) { + UnsetVarStruct(varPtr, NULL, iPtr, VarHashGetKey(varPtr), + NULL, TCL_TRACE_UNSETS, -1); + } + + VarHashRefCount(varPtr)--; VarHashDeleteEntry(varPtr); } VarHashDeleteTable(tablePtr); -- cgit v0.12 From 69e6c8e2f7cc9c7cd816bb7acfe52c7b4556e4cb Mon Sep 17 00:00:00 2001 From: dgp Date: Thu, 8 Sep 2016 02:34:37 +0000 Subject: New test trace-18.5 for the bug. Updated trace-18.1 which was tuned to it. --- tests/trace.test | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/trace.test b/tests/trace.test index 1099f48..3b69d38 100644 --- a/tests/trace.test +++ b/tests/trace.test @@ -1227,7 +1227,7 @@ test trace-17.3 {traced variables must survive procedure exits} { test trace-18.1 {unset traces on procedure returns} { proc p1 {x y} {set a 44; p2 14} - proc p2 {z} {trace add variable z unset {traceCheck {lsort [uplevel 1 {info vars}]}}} + proc p2 {z} {trace add variable z unset {traceCheck {lsort [uplevel 2 {info vars}]}}} set info {} p1 foo bar set info @@ -1263,6 +1263,27 @@ test trace-18.4 {namespace delete / trace vdelete combo, Bug \#1338280} { rename doTrace {} set info } 1110 +test trace-18.5 {Bug 7f02ff1efa} -setup { + proc constant {name value} { + upvar 1 $name c + set c $value + trace variable c wu [list reset $value] + } + proc reset {v a i o} { + uplevel 1 [list constant $a $v] + } + proc demo {} { + constant pi 3.14 + } +} -body { + unset -nocomplain pi + demo + info exists pi +} -cleanup { + rename demo {} + rename reset {} + rename constant {} +} -result 0 # Delete arrays when done, so they can be re-used as scalars # elsewhere. -- cgit v0.12