From f606211e0c51995aea56b201d27556a45c10109c Mon Sep 17 00:00:00 2001 From: Miguel Sofer Date: Sun, 23 May 2004 22:53:18 +0000 Subject: * generic/tclNamesp.c (Tcl_FindNamespaceVar): [Bug 959052] fixed, insuring that no "zombie" variables are found. * generic/tclVar.c (TclLookupSimpleVar): comments re [Bug 736729] (predecessor of [Bug 959052]) removed. * tests/namespace.test: added tests 17.10-12 --- ChangeLog | 8 ++++++++ generic/tclNamesp.c | 19 ++++++++++++++++++- generic/tclVar.c | 22 +++++----------------- tests/namespace.test | 26 +++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4931461..0c77a8c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2004-05-23 Miguel Sofer + + * generic/tclNamesp.c (Tcl_FindNamespaceVar): [Bug 959052] fixed, + insuring that no "zombie" variables are found. + * generic/tclVar.c (TclLookupSimpleVar): comments re [Bug 736729] + (predecessor of [Bug 959052]) removed. + * tests/namespace.test: added tests 17.10-12 + 2004-05-22 Miguel Sofer * generic/tclVar.c (TclObjLookupVar, TclObjUnsetVar2): fix for new diff --git a/generic/tclNamesp.c b/generic/tclNamesp.c index ded1f96..c369ccf 100644 --- a/generic/tclNamesp.c +++ b/generic/tclNamesp.c @@ -21,7 +21,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclNamesp.c,v 1.37 2004/03/24 21:54:32 dkf Exp $ + * RCS: @(#) $Id: tclNamesp.c,v 1.38 2004/05/23 22:53:20 msofer Exp $ */ #include "tclInt.h" @@ -2324,6 +2324,23 @@ Tcl_FindNamespaceVar(interp, name, contextNsPtr, flags) simpleName); if (entryPtr != NULL) { varPtr = (Var *) Tcl_GetHashValue(entryPtr); + + /* Fix for [Bug 959052]. + * When a varName is looked from a namespace different from the + * global one, there is no corresponding variable in the namespace and + * there is a "zombie" variable in the global namespace (ie, the + * varName is in the hash table, but the variable is unset), this code + * returns a reference to the zombie. Except when the zombie was + * created by a [variable] call, it should instead create a + * variable in the namespace. + * In particular, zombies created by [trace], [upvar], [global] or + * a reference in a tclNsVarNameType obj should never be found. + */ + if (TclIsVarUndefined(varPtr) + && !(varPtr->flags & VAR_NAMESPACE_VAR) + && !(flags & (TCL_GLOBAL_ONLY|TCL_NAMESPACE_ONLY))) { + varPtr = NULL; + } } } } diff --git a/generic/tclVar.c b/generic/tclVar.c index 9097fd1..e84ce8f 100644 --- a/generic/tclVar.c +++ b/generic/tclVar.c @@ -15,7 +15,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclVar.c,v 1.81 2004/05/22 16:21:17 msofer Exp $ + * RCS: @(#) $Id: tclVar.c,v 1.82 2004/05/23 22:53:20 msofer Exp $ */ #include "tclInt.h" @@ -758,30 +758,18 @@ TclLookupSimpleVar(interp, varName, flags, create, errMsgPtr, indexPtr) } } - /* - * FIXME: [Bug 736729] - * - * When a varName is looked from a namespace different from the - * global one, there is no corresponding variable in the namespace and - * there is a "zombie" variable in the global namespace (ie, the - * varName is in the hash table, but the variable is unset), this code - * returns a reference to the zombie. It should instead create a - * variable in the namespace. - * - * Fix in progress - that it is not here yet may indicate that the - * picture above is incomplete or wrong. - * - Miguel Sofer, 2004-05-22 - */ - /* * Don't pass TCL_LEAVE_ERR_MSG, we may yet create the variable, * or otherwise generate our own error! */ + var = Tcl_FindNamespaceVar(interp, varName, (Tcl_Namespace *) cxtNsPtr, flags & ~TCL_LEAVE_ERR_MSG); + if (var != (Tcl_Var) NULL) { varPtr = (Var *) var; } + if (varPtr == NULL) { if (create) { /* var wasn't found so create it */ TclGetNamespaceForQualName(interp, varName, cxtNsPtr, @@ -799,7 +787,7 @@ TclLookupSimpleVar(interp, varName, flags, create, errMsgPtr, indexPtr) Tcl_SetHashValue(hPtr, varPtr); varPtr->hPtr = hPtr; varPtr->nsPtr = varNsPtr; - if ((lookGlobal) || (varNsPtr == NULL)) { + if (lookGlobal) { /* * The variable was created starting from the global * namespace: a global reference is returned even if diff --git a/tests/namespace.test b/tests/namespace.test index 941fad5..7e82ccb 100644 --- a/tests/namespace.test +++ b/tests/namespace.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: namespace.test,v 1.25 2004/05/22 00:10:54 msofer Exp $ +# RCS: @(#) $Id: namespace.test,v 1.26 2004/05/23 22:53:21 msofer Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2 @@ -560,6 +560,30 @@ test namespace-17.9 {Tcl_FindNamespaceVar, relative name and TCL_GLOBAL_ONLY} { } set test_ns_1::a } {hello} +test namespace-17.10 {Tcl_FindNamespaceVar, do not find zombies (Bug 959052)} { + catch {unset x} + catch {namespace delete test_ns_1 } + catch {namespace delete test_ns_2} + namespace eval test_ns_1 upvar x q + namespace eval test_ns_2 set x 1 + catch {set ::x} +} 1 +test namespace-17.11 {Tcl_FindNamespaceVar, do not find zombies (Bug 959052)} { + catch {unset x} + catch {namespace delete test_ns_1} + trace add variable x write {;#} + namespace eval test_ns_1 set x 1 + catch {set ::x} +} 1 +test namespace-17.12 {Tcl_FindNamespaceVar, do not find zombies (Bug 959052)} { + catch {unset x} + catch {namespace delete test_ns_1} + namespace eval test_ns_1 {trace add variable x write {;#}} + set ::x 0 + namespace eval test_ns_1 set x 1 + set ::x +} 1 + catch {unset x} catch {unset l} -- cgit v0.12