From 1e0d2b0d7e8ab7298e67f921a156697fcc433d06 Mon Sep 17 00:00:00 2001 From: Philippe Altherr Date: Sun, 26 Oct 2025 14:06:57 -0700 Subject: 53781: fix loading of autoload variable via a reference --- ChangeLog | 2 ++ Src/params.c | 29 ++++++++++++++++---------- Test/B02typeset.ztst | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++ Test/K01nameref.ztst | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 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 * 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 -- cgit v1.2.3-70-g09d2