summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Altherr <philippe.altherr@gmail.com>2025-10-26 14:06:57 -0700
committerBart Schaefer <schaefer@zsh.org>2025-10-26 14:06:57 -0700
commit1e0d2b0d7e8ab7298e67f921a156697fcc433d06 (patch)
tree40d51f08a80d19901b3b24ba41a6c5252ee5c22b
parent53732: avoid tail-call exec in always block (diff)
downloadzsh-1e0d2b0d7e8ab7298e67f921a156697fcc433d06.tar
zsh-1e0d2b0d7e8ab7298e67f921a156697fcc433d06.tar.gz
zsh-1e0d2b0d7e8ab7298e67f921a156697fcc433d06.tar.bz2
zsh-1e0d2b0d7e8ab7298e67f921a156697fcc433d06.tar.lz
zsh-1e0d2b0d7e8ab7298e67f921a156697fcc433d06.tar.xz
zsh-1e0d2b0d7e8ab7298e67f921a156697fcc433d06.tar.zst
zsh-1e0d2b0d7e8ab7298e67f921a156697fcc433d06.zip
53781: fix loading of autoload variable via a reference
-rw-r--r--ChangeLog2
-rw-r--r--Src/params.c29
-rw-r--r--Test/B02typeset.ztst57
-rw-r--r--Test/K01nameref.ztst58
4 files changed, 135 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index ab940073b..f5a00430b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,8 @@
* Philippe: 53732: avoid tail-call exec in always block
+ * Philippe: 53781: fix loading of autoload variable via a reference
+
2025-10-24 Oliver Kiddle <opk@zsh.org>
* 54002: Src/parse.c: silence compiler warning for static function
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