Tcl Source Code

Artifact [5464f42ccd]
Login

Artifact 5464f42ccd82425c193e05d1ad9acffe372d8834:

Attachment "959052.patch" to ticket [959052ffff] added by msofer 2004-05-24 05:48:50.
Index: generic/tclNamesp.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclNamesp.c,v
retrieving revision 1.37
diff -u -r1.37 tclNamesp.c
--- generic/tclNamesp.c	24 Mar 2004 21:54:32 -0000	1.37
+++ generic/tclNamesp.c	23 May 2004 22:38:05 -0000
@@ -2324,6 +2324,23 @@
 		    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;
+		}		
             }
         }
     }
Index: generic/tclVar.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclVar.c,v
retrieving revision 1.81
diff -u -r1.81 tclVar.c
--- generic/tclVar.c	22 May 2004 16:21:17 -0000	1.81
+++ generic/tclVar.c	23 May 2004 22:38:08 -0000
@@ -758,30 +758,18 @@
 	    }
 	} 
 
-	/*
-	 * 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 @@
 		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 
Index: tests/namespace.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/namespace.test,v
retrieving revision 1.25
diff -u -r1.25 namespace.test
--- tests/namespace.test	22 May 2004 00:10:54 -0000	1.25
+++ tests/namespace.test	23 May 2004 22:38:09 -0000
@@ -560,6 +560,30 @@
     }
     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}