summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilippe Altherr <philippe.altherr@gmail.com>2025-10-26 16:52:51 -0700
committerBart Schaefer <schaefer@zsh.org>2025-10-26 16:52:51 -0700
commite1fed5439c5fb844a028af3ac58d5032cc307df7 (patch)
tree6e11cfa88243536345729caeeb38ab4c8af78adb
parent53781: fix loading of autoload variable via a reference (diff)
downloadzsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar
zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.gz
zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.bz2
zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.lz
zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.xz
zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.tar.zst
zsh-e1fed5439c5fb844a028af3ac58d5032cc307df7.zip
53782: Src/params.c, Test/K01nameref.ztst: changes to nameref base level:
- avoid changing base on assignment; - omit base level for up-scope references - do not follow reference chains for base level of new references
-rw-r--r--ChangeLog11
-rw-r--r--Src/params.c90
-rw-r--r--Test/K01nameref.ztst53
3 files changed, 103 insertions, 51 deletions
diff --git a/ChangeLog b/ChangeLog
index f5a00430b..5854f4250 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,15 @@
2025-10-26 Bart Schaefer <schaefer@zsh.org>
- * Philippe: 53732: avoid tail-call exec in always block
+ * Philippe: 53732: Src/loop.c, Test/A01grammar.ztst: avoid tail-call
+ exec in always block
- * Philippe: 53781: fix loading of autoload variable via a reference
+ * Philippe: 53781: Src/params.c, Test/B02typeset.ztst,
+ Test/K01nameref.ztst: fix load of autoload variable via a reference
+
+ * Philippe: 53782: Src/params.c, Test/K01nameref.ztst: changes to
+ handling of nameref base level: avoid changing base on assignment;
+ omit base level for up-scope references; do not follow reference
+ chains when computing base level of new references
2025-10-24 Oliver Kiddle <opk@zsh.org>
diff --git a/Src/params.c b/Src/params.c
index 70042a417..6945e73e9 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2239,10 +2239,10 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
}
Param p1 = (Param)gethashnode2(paramtab, ref);
if (p1) {
- int scope = ((pm->node.flags & PM_NAMEREF) ?
- ((pm->node.flags & PM_UPPER) ? -(pm->base) :
- pm->base) : locallevel);
- pm = upscope(p1, scope);
+ if (pm->node.flags & PM_UPPER)
+ pm = upscope_upper(p1, pm->level - 1);
+ else
+ pm = upscope(p1, pm->base);
pm = (Param)loadparamnode(paramtab, pm, ref);
}
if (!(p1 && pm) ||
@@ -3324,7 +3324,11 @@ assignsparam(char *s, char *val, int flags)
}
}
+ if (v->pm->node.flags & PM_NAMEREF)
+ v->pm->node.flags |= PM_NEWREF;
assignstrvalue(v, val, flags);
+ if (v->pm->node.flags & PM_NAMEREF)
+ v->pm->node.flags &= ~PM_NEWREF;
unqueue_signals();
return v->pm;
}
@@ -6314,12 +6318,13 @@ resolve_nameref(Param pm, const Asgment stop)
} else if ((hn = gethashnode2(realparamtab, seek))) {
if (pm) {
if (!(stop && (stop->flags & (PM_LOCAL)))) {
- int scope = ((pm->node.flags & PM_NAMEREF) ?
- ((pm->node.flags & PM_UPPER) ?
- /* pm->base == 0 means not set yet */
- -(pm->base ? pm->base : pm->level) :
- pm->base) : ((Param)hn)->level);
- hn = (HashNode)upscope((Param)hn, scope);
+ if ((pm->node.flags & PM_NAMEREF) &&
+ (pm->node.flags & PM_UPPER))
+ hn = (HashNode)upscope_upper((Param)hn, pm->level - 1);
+ else
+ hn = (HashNode)upscope((Param)hn,
+ (pm->node.flags & PM_NAMEREF) ?
+ (pm->base) : ((Param)hn)->level);
}
hn = loadparamnode(paramtab, (Param)hn, seek);
/* user can't tag a nameref, safe for loop detection */
@@ -6374,12 +6379,37 @@ setscope(Param pm)
char *t = refname ? itype_end(refname, INAMESPC, 0) : NULL;
int q = queue_signal_level();
+ /* Compute pm->width */
/* Temporarily change nameref to array parameter itself */
if (t && *t == '[')
*t = 0;
else
t = 0;
- stop.name = "";
+ if (t) {
+ pm->width = t - refname;
+ *t = '[';
+ refname = dupstrpfx(refname, pm->width);
+ }
+
+ /* Compute pm->base */
+ if (!(pm->node.flags & PM_UPPER) && refname &&
+ (basepm = (Param)gethashnode2(realparamtab, refname)) &&
+ (basepm = (Param)loadparamnode(realparamtab, basepm, refname)) &&
+ (!(basepm->node.flags & PM_NEWREF) || (basepm = basepm->old))) {
+ pm->base = basepm->level;
+ }
+ if (pm->base > pm->level) {
+ if (EMULATION(EMULATE_KSH)) {
+ zerr("%s: global reference cannot refer to local variable",
+ pm->node.nam);
+ unsetparam_pm(pm, 0, 1);
+ } else if (isset(WARNNESTEDVAR))
+ zwarn("reference %s in enclosing scope set to local variable %s",
+ pm->node.nam, refname);
+ }
+
+ /* Check for self references */
+ stop.name = pm->node.nam;
stop.value.scalar = NULL;
stop.flags = PM_NAMEREF;
if (locallevel && !(pm->node.flags & PM_UPPER))
@@ -6387,11 +6417,6 @@ setscope(Param pm)
dont_queue_signals(); /* Prevent unkillable loops */
basepm = (Param)resolve_nameref(pm, &stop);
restore_queue_signals(q);
- if (t) {
- pm->width = t - refname;
- *t = '[';
- refname = dupstrpfx(refname, pm->width);
- }
if (basepm) {
if (basepm->node.flags & PM_NAMEREF) {
if (pm == basepm) {
@@ -6419,27 +6444,7 @@ setscope(Param pm)
break;
}
}
- } else if (!pm->base) {
- pm->base = basepm->level;
- if ((pm->node.flags & PM_UPPER) &&
- (basepm = upscope(basepm, -(pm->level))))
- pm->base = basepm->level;
}
- } else if (pm->base < locallevel && refname &&
- (basepm = (Param)getparamnode(realparamtab, refname))) {
- pm->base = basepm->level;
- if ((pm->node.flags & PM_UPPER) &&
- (basepm = upscope(basepm, -(pm->level))))
- pm->base = basepm->level;
- }
- if (pm->base > pm->level) {
- if (EMULATION(EMULATE_KSH)) {
- zerr("%s: global reference cannot refer to local variable",
- pm->node.nam);
- unsetparam_pm(pm, 0, 1);
- } else if (isset(WARNNESTEDVAR))
- zwarn("reference %s in enclosing scope set to local variable %s",
- pm->node.nam, refname);
}
if (refname && upscope(pm, pm->base) == pm &&
strcmp(pm->node.nam, refname) == 0) {
@@ -6456,13 +6461,18 @@ upscope(Param pm, int reflevel)
{
Param up = pm->old;
while (up && up->level >= reflevel) {
- if (reflevel < 0 && up->level < -(reflevel))
- break;
pm = up;
up = up->old;
}
- if (reflevel < 0 && locallevel > 0)
- return pm->level == locallevel ? up : pm;
+ return pm;
+}
+
+/**/
+mod_export Param
+upscope_upper(Param pm, int reflevel)
+{
+ while (pm && pm->level > reflevel)
+ pm = pm->old;
return pm;
}
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 52aed0af0..b03487d03 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -1100,15 +1100,15 @@ F:previously this could create an infinite recursion and crash
>h:1: rs= - ra= - rs1= - ra1=
>h:2: rs= - ra= - rs1= - ra1=
>i:1: rs= - ra= - rs1= - ra1=
->i:2: rs=g - ra=g - rs1=g - ra1=g
->j:1: rs=g - ra=g - rs1=g - ra1=g
->j:2: rs=g - ra=g - rs1=g - ra1=g
->i:3: rs=g - ra=g - rs1=g - ra1=g
->k:1: rs=g - ra=g - rs1=g - ra1=g
->k:2: rs=g - ra=g - rs1=g - ra1=g
->h:3: rs=g - ra=g - rs1=g - ra1=g
->k:1: rs=g - ra=g - rs1=g - ra1=g
->k:2: rs=g - ra=g - rs1=g - ra1=g
+>i:2: rs=f - ra=f - rs1=f - ra1=f
+>j:1: rs=f - ra=f - rs1=f - ra1=f
+>j:2: rs=f - ra=f - rs1=f - ra1=f
+>i:3: rs=f - ra=f - rs1=f - ra1=f
+>k:1: rs=f - ra=f - rs1=f - ra1=f
+>k:2: rs=f - ra=f - rs1=f - ra1=f
+>h:3: rs=f - ra=f - rs1=f - ra1=f
+>k:1: rs=f - ra=f - rs1=f - ra1=f
+>k:2: rs=f - ra=f - rs1=f - ra1=f
>g:3: rs=f - ra=f - rs1=f - ra1=f
e '' 6
@@ -1237,4 +1237,39 @@ F:previously this could create an infinite recursion and crash
?(eval):zsh/random:6: error when adding parameter `SRANDOM'
?(eval):6: autoloading module zsh/random failed to define parameter: SRANDOM
+ () {
+ typeset var1=var1
+ typeset var2=var2
+ typeset -n ref1=var1
+ echo "ref1=$ref1";
+ () {
+ typeset -n ref1=var2
+ typeset -n ref2=ref1
+ echo "ref1=$ref1";
+ echo "ref2=$ref2";
+ }
+ }
+0:regression: don't follow references when computing base scope - part 1
+>ref1=var1
+>ref1=var2
+>ref2=var2
+
+ () {
+ typeset var1=var1
+ typeset -n ref1=var1
+ echo ref1=$ref1;
+ () {
+ typeset var2=var2
+ typeset -n ref1
+ typeset -n ref2=ref1
+ ref1=var2
+ echo ref1=$ref1;
+ echo ref2=$ref2;
+ }
+ }
+0:regression: don't follow references when computing base scope - part 2
+>ref1=var1
+>ref1=var2
+>ref2=var2
+
%clean