Attachment "diff" to
ticket [631741ffff]
added by
msofer
2003-03-25 04:34:58.
Index: generic/tclVar.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclVar.c,v
retrieving revision 1.69
diff -u -r1.69 tclVar.c
--- generic/tclVar.c 12 Nov 2002 02:23:03 -0000 1.69
+++ generic/tclVar.c 24 Mar 2003 00:39:51 -0000
@@ -21,6 +21,7 @@
#include "tclInt.h"
#include "tclPort.h"
+
/*
* The strings below are used to indicate what went wrong when a
* variable access is denied.
@@ -55,7 +56,7 @@
static int ObjMakeUpvar _ANSI_ARGS_((Tcl_Interp *interp,
CallFrame *framePtr, Tcl_Obj *otherP1Ptr,
CONST char *otherP2, CONST int otherFlags,
- CONST char *myName, CONST int myFlags, int index));
+ CONST char *myName, int myFlags, int index));
static Var * NewVar _ANSI_ARGS_((void));
static ArraySearch * ParseSearchId _ANSI_ARGS_((Tcl_Interp *interp,
CONST Var *varPtr, CONST char *varName,
@@ -596,6 +597,16 @@
}
/*
+ * This flag bit should not interfere with TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
+ * or TCL_LEAVE_ERR_MSG; it signals that the variable lookup is performed for
+ * upvar (or similar) purposes, with slightly different rules:
+ * - Bug #696893 - variable is either proc-local or in the current
+ * namespace; never follow the second (global) resolution path
+ * - Bug #631741 - do not use special namespace or interp resolvers
+ */
+#define LOOKUP_FOR_UPVAR 0x400
+
+/*
*----------------------------------------------------------------------
*
* TclLookupSimpleVar --
@@ -642,7 +653,8 @@
CONST char *varName; /* This is a simple variable name that could
* representa scalar or an array. */
int flags; /* Only TCL_GLOBAL_ONLY, TCL_NAMESPACE_ONLY,
- * and TCL_LEAVE_ERR_MSG bits matter. */
+ * LOOKUP_FOR_UPVAR and TCL_LEAVE_ERR_MSG bits
+ * matter. */
CONST int create; /* If 1, create hash table entry for varname,
* if it doesn't already exist. If 0, return
* error if it doesn't exist. */
@@ -669,19 +681,21 @@
varNsPtr = NULL; /* set non-NULL if a nonlocal variable */
*indexPtr = -3;
+ if ((flags & TCL_GLOBAL_ONLY) || iPtr->varFramePtr == NULL) {
+ cxtNsPtr = iPtr->globalNsPtr;
+ } else {
+ cxtNsPtr = iPtr->varFramePtr->nsPtr;
+ }
+
/*
* If this namespace has a variable resolver, then give it first
* crack at the variable resolution. It may return a Tcl_Var
* value, it may signal to continue onward, or it may signal
* an error.
*/
- if ((flags & TCL_GLOBAL_ONLY) || iPtr->varFramePtr == NULL) {
- cxtNsPtr = iPtr->globalNsPtr;
- } else {
- cxtNsPtr = iPtr->varFramePtr->nsPtr;
- }
- if (cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL) {
+ if ((cxtNsPtr->varResProc != NULL || iPtr->resolverPtr != NULL)
+ && !(flags & LOOKUP_FOR_UPVAR)) {
resPtr = iPtr->resolverPtr;
if (cxtNsPtr->varResProc) {
@@ -736,10 +750,15 @@
|| ((*varName == ':') && (*(varName+1) == ':'));
if (lookGlobal) {
*indexPtr = -1;
- flags = (flags | TCL_GLOBAL_ONLY) & ~TCL_NAMESPACE_ONLY;
- } else if (flags & TCL_NAMESPACE_ONLY) {
- *indexPtr = -2;
- }
+ flags = (flags | TCL_GLOBAL_ONLY) & ~(TCL_NAMESPACE_ONLY|LOOKUP_FOR_UPVAR);
+ } else {
+ if (flags & LOOKUP_FOR_UPVAR) {
+ flags = (flags | TCL_NAMESPACE_ONLY) & ~LOOKUP_FOR_UPVAR;
+ }
+ if (flags & TCL_NAMESPACE_ONLY) {
+ *indexPtr = -2;
+ }
+ }
/*
* Don't pass TCL_LEAVE_ERR_MSG, we may yet create the variable,
@@ -3458,7 +3477,7 @@
* indicates scope of "other" variable. */
CONST char *myName; /* Name of variable which will refer to
* otherP1/otherP2. Must be a scalar. */
- CONST int myFlags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
+ int myFlags; /* 0, TCL_GLOBAL_ONLY or TCL_NAMESPACE_ONLY:
* indicates scope of myName. */
int index; /* If the variable to be linked is an indexed
* scalar, this is its index. Otherwise, -1. */
@@ -3490,7 +3509,7 @@
if (index >= 0) {
if (!varFramePtr->isProcCallFrame) {
- panic("ObjMakeUpVar called with an index outside from a proc.\n");
+ panic("ObjMakeUpvar called with an index outside from a proc.\n");
}
varPtr = &(varFramePtr->compiledLocals[index]);
} else {
@@ -3513,11 +3532,16 @@
}
/*
- * Lookup and eventually create the new variable.
+ * Lookup and eventually create the new variable. Set the flag bit
+ * LOOKUP_FOR_UPVAR to indicate the special resolution rules for
+ * upvar purposes:
+ * - Bug #696893 - variable is either proc-local or in the current
+ * namespace; never follow the second (global) resolution path
+ * - Bug #631741 - do not use special namespace or interp resolvers
*/
- varPtr = TclLookupSimpleVar(interp, myName, myFlags, /*create*/ 1,
- &errMsg, &index);
+ varPtr = TclLookupSimpleVar(interp, myName, (myFlags | LOOKUP_FOR_UPVAR),
+ /* create */ 1, &errMsg, &index);
if (varPtr == NULL) {
VarErrMsg(interp, myName, NULL, "create", errMsg);
return TCL_ERROR;
Index: tests/var.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/var.test,v
retrieving revision 1.20
diff -u -r1.20 var.test
--- tests/var.test 17 Oct 2002 17:41:45 -0000 1.20
+++ tests/var.test 24 Mar 2003 00:39:51 -0000
@@ -262,6 +262,16 @@
set aaaaa 789789
list [catch {upvar #0 aaaaa test_ns_fred::lnk} msg] $msg
} {1 {can't create "test_ns_fred::lnk": parent namespace doesn't exist}}
+test var-3.10 {MakeUpvar, } {
+ namespace eval {} {
+ set bar 0
+ namespace eval foo upvar bar bar
+ set foo::bar 1
+ catch {list $bar $foo::bar} msg
+ unset ::aaaaa
+ set msg
+ }
+} {1 1}
if {[info commands testgetvarfullname] != {}} {
test var-4.1 {Tcl_GetVariableName, global variable} {