Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: Fix loading of autoload variable accessed via a reference



When a reference to an autoload variable is defined, the autoload variable should be loaded. The autoload variable should also be loaded whenever such a reference is dereferenced. The latter is currently failing if the reference includes a subscript. The latter is also failing and produces bogus results when the autoload variable is hidden by a local variable. In this case it fails both with and without subscript.

The patch fixes these issues. It introduces a new loadparamnode function, which is a more sensible alternative to the getparamnode_nofollow function introduced in the original patches for setscope (workers/53688).

Below are 3 examples that exhibit the issues:

Example

zmodload -u zsh/random

echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}

typeset -n ref=SRANDOM[1,20]

echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}

echo v=${ref/<->/integer}

zmodload -u zsh/random

echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}

echo v=${ref/<->/integer}


Current output

Expected output

z=SRANDOM (zsh/random)

z=

v=integer

z=SRANDOM (zsh/random)

v=zsh/random

z=SRANDOM (zsh/random)

z=

v=integer

z=SRANDOM (zsh/random)

v=integer


Example

() {

  typeset -n ref=SRANDOM

  echo v=${ref/<->/integer}

  zmodload -u zsh/random

  echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}

  typeset -h SRANDOM=local-variable

  echo v=${ref/<->/integer}

  echo NOT REACHED

}


Current output

Expected output

v=integer

z=SRANDOM (zsh/random)

v=local-variable

NOT REACHED

v=integer

z=SRANDOM (zsh/random)

<error-message>


Example

() {

  typeset -n ref=SRANDOM[1,20]

  echo v=${ref/<->/integer}

  zmodload -u zsh/random

  echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}

  typeset -h SRANDOM=local-variable

  echo v=${ref/<->/integer}

  echo NOT REACHED

}


Current output

Expected output

v=integer

z=SRANDOM (zsh/random)

v=zsh/random

NOT REACHED

v=integer

z=SRANDOM (zsh/random)

<error-message>


Philippe


diff --git a/Src/params.c b/Src/params.c
index 7b515515e..70042a417 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -525,18 +525,18 @@ newparamtable(int size, char const *name)
 
 /**/
 static HashNode
-getparamnode(HashTable ht, const char *nam)
+loadparamnode(HashTable ht, Param pm, const char *nam)
 {
-    HashNode hn = gethashnode2(ht, nam);
-    Param pm = (Param) hn;
-
     if (pm && (pm->node.flags & PM_AUTOLOAD) && pm->u.str) {
+	int level = pm->level;
 	char *mn = dupstring(pm->u.str);
-
-	(void)ensurefeature(mn, "p:", (pm->node.flags & PM_AUTOALL) ? NULL :
-			    nam);
-	hn = gethashnode2(ht, nam);
-	if (!hn) {
+	(void)ensurefeature(mn, "p:", nam);
+	pm = (Param)gethashnode2(ht, nam);
+	while (pm && pm->level > level)
+	    pm = pm->old;
+	if (pm && (pm->level != level || (pm->node.flags & PM_AUTOLOAD)))
+	    pm = NULL;
+	if (!pm) {
 	    /*
 	     * This used to be a warning, but surely if we allow
 	     * stuff to go ahead with the autoload stub with
@@ -546,7 +546,14 @@ getparamnode(HashTable ht, const char *nam)
 		 nam);
 	}
     }
+    return (HashNode)pm;
+}
 
+/**/
+static HashNode
+getparamnode(HashTable ht, const char *nam)
+{
+    HashNode hn = loadparamnode(ht, (Param)gethashnode2(ht, nam), nam);
     if (hn && ht == realparamtab && !(hn->flags & PM_UNSET))
 	hn = resolve_nameref((Param)hn, NULL);
     return hn;
@@ -2236,6 +2243,7 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
 				 ((pm->node.flags & PM_UPPER) ? -(pm->base) :
 				  pm->base) : locallevel);
 		    pm = upscope(p1, scope);
+		    pm = (Param)loadparamnode(paramtab, pm, ref);
 		}
 		if (!(p1 && pm) ||
 		    ((pm->node.flags & PM_UNSET) &&
@@ -6313,12 +6321,11 @@ resolve_nameref(Param pm, const Asgment stop)
 				  pm->base) : ((Param)hn)->level);
 		    hn = (HashNode)upscope((Param)hn, scope);
 		}
+		hn = loadparamnode(paramtab, (Param)hn, seek);
 		/* user can't tag a nameref, safe for loop detection */
 		pm->node.flags |= PM_TAGGED;
 	    }
 	    if (hn) {
-		if (hn->flags & PM_AUTOLOAD)
-		    hn = getparamnode(realparamtab, seek);
 		if (!(hn->flags & PM_UNSET))
 		    hn = resolve_nameref((Param)hn, stop);
 	    }
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index 914eea92b..7cca2bd81 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -1120,3 +1120,60 @@
 1:Regression test for {...} parsing in typeset
 ?(eval):typeset:2: not valid in this context: {X}
 ?(eval):typeset:3: not valid in this context: {X}
+
+ zmodload -u zsh/random
+ echo v=${SRANDOM/<->/integer}
+ typeset SRANDOM
+ echo v=${SRANDOM/<->/integer}
+0:Global non -h variable doesn't hide special variable
+>v=integer
+>v=integer
+
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ typeset -g SRANDOM
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ echo v=${SRANDOM/<->/integer}
+0:Global non -h variable doesn't hide autoload variable
+>z=SRANDOM (zsh/random)
+>z=SRANDOM (zsh/random)
+>v=integer
+
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ typeset -gh SRANDOM
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ echo v=${SRANDOM/<->/integer}
+0:Global -h variable doesn't hide autoload variable
+>z=SRANDOM (zsh/random)
+>z=SRANDOM (zsh/random)
+>v=integer
+
+ zmodload -u zsh/random
+ echo v=${SRANDOM/<->/integer}
+ typeset SRANDOM
+ echo v=${SRANDOM/<->/integer}
+0:Local non -h variable doesn't hide special variable
+>v=integer
+>v=integer
+
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ typeset SRANDOM
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ echo v=${SRANDOM/<->/integer}
+0:Local non -h variable hides autoload variable
+F:This is a bug, the non -h variable should not hide the autoload variable
+>z=SRANDOM (zsh/random)
+>z=
+>v=
+
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ typeset -h SRANDOM
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ echo v=${SRANDOM/<->/integer}
+0:Local -h variable hides autoload variable
+>z=SRANDOM (zsh/random)
+>z=
+>v=
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 54f0aaf68..52aed0af0 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -1179,4 +1179,62 @@ F:previously this could create an infinite recursion and crash
 >typeset PS1=zz
 *?*
 
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ typeset -n ref=SRANDOM
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ echo v=${ref/<->/integer}
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ echo v=${ref/<->/integer}
+0:Referring and dereferring an autoload variable loads it (direct)
+>z=SRANDOM (zsh/random)
+>z=
+>v=integer
+>z=SRANDOM (zsh/random)
+>v=integer
+
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ typeset -n ref=SRANDOM[1,20]
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ echo v=${ref/<->/integer}
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ echo v=${ref/<->/integer}
+0:Referring and dereferring an autoload variable loads it (subscript)
+>z=SRANDOM (zsh/random)
+>z=
+>v=integer
+>z=SRANDOM (zsh/random)
+>v=integer
+
+ typeset -n ref=SRANDOM
+ echo v=${ref/<->/integer}
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ typeset -h SRANDOM=local-variable
+ echo v=${ref/<->/integer}
+ echo NOT REACHED
+1:Dereferring an autoload variable fails to load it if its hidden (direct)
+>v=integer
+>z=SRANDOM (zsh/random)
+?(eval):6: Can't add module parameter `SRANDOM': local parameter exists
+?(eval):zsh/random:6: error when adding parameter `SRANDOM'
+?(eval):6: autoloading module zsh/random failed to define parameter: SRANDOM
+
+ typeset -n ref=SRANDOM[1,20]
+ echo v=${ref/<->/integer}
+ zmodload -u zsh/random
+ echo z=${(M)${(f)${ zmodload -ap}}:#*SRANDOM*}
+ typeset -h SRANDOM=local-variable
+ echo v=${ref/<->/integer}
+ echo NOT REACHED
+1:Dereferring an autoload variable fails to load it if its hidden (subscript)
+>v=integer
+>z=SRANDOM (zsh/random)
+?(eval):6: Can't add module parameter `SRANDOM': local parameter exists
+?(eval):zsh/random:6: error when adding parameter `SRANDOM'
+?(eval):6: autoloading module zsh/random failed to define parameter: SRANDOM
+
 %clean


Messages sorted by: Reverse Date, Date, Thread, Author