summaryrefslogtreecommitdiffstats
path: root/Src
diff options
context:
space:
mode:
authorBart Schaefer <schaefer@zsh.org>2025-05-06 10:46:23 -0700
committerBart Schaefer <schaefer@zsh.org>2025-05-06 10:50:53 -0700
commitf555e902db1e4acec7961374153ec19843e2833a (patch)
tree1f0cc5ac9e804601cf41f19abfbc2921b42b39c4 /Src
parent53535: fix builds with interactive manpagers (diff)
downloadzsh-f555e902db1e4acec7961374153ec19843e2833a.tar
zsh-f555e902db1e4acec7961374153ec19843e2833a.tar.gz
zsh-f555e902db1e4acec7961374153ec19843e2833a.tar.bz2
zsh-f555e902db1e4acec7961374153ec19843e2833a.tar.lz
zsh-f555e902db1e4acec7961374153ec19843e2833a.tar.xz
zsh-f555e902db1e4acec7961374153ec19843e2833a.tar.zst
zsh-f555e902db1e4acec7961374153ec19843e2833a.zip
53546,53557 (plus test): Fix scoping of "placeholder" named references
When using placeholders declared several levels earlier than assignment: 1) Searching "up" for "typeset -n -u" could find deeper locals than intended 2) Searching for a subscript reference could skip to the top level 3) Exiting a function scope could incorrectly change the reference level
Diffstat (limited to 'Src')
-rw-r--r--Src/params.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/Src/params.c b/Src/params.c
index c10236a0d..e6fb7fcd0 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2231,7 +2231,13 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
*ss = 0;
}
Param p1 = (Param)gethashnode2(paramtab, ref);
- if (!(p1 && (pm = upscope(p1, pm->base))) ||
+ if (p1) {
+ int scope = ((pm->node.flags & PM_NAMEREF) ?
+ ((pm->node.flags & PM_UPPER) ? -(pm->base) :
+ pm->base) : locallevel);
+ pm = upscope(p1, scope);
+ }
+ if (!(p1 && pm) ||
((pm->node.flags & PM_UNSET) &&
!(pm->node.flags & PM_DECLARED)))
return NULL;
@@ -5885,7 +5891,8 @@ scanendscope(HashNode hn, UNUSED(int flags))
export_param(pm);
} else
unsetparam_pm(pm, 0, 0);
- } else if ((pm->node.flags & PM_NAMEREF) && pm->base > pm->level)
+ } else if ((pm->node.flags & PM_NAMEREF) &&
+ pm->base > pm->level && pm->base > locallevel)
pm->base = locallevel;
}
@@ -6291,7 +6298,7 @@ resolve_nameref(Param pm, const Asgment stop)
if (pm) {
if (!(stop && (stop->flags & (PM_LOCAL)))) {
int scope = ((pm->node.flags & PM_NAMEREF) ?
- ((pm->node.flags & PM_UPPER) ? -1 :
+ ((pm->node.flags & PM_UPPER) ? -(pm->base) :
pm->base) : ((Param)hn)->level);
hn = (HashNode)upscope((Param)hn, scope);
}
@@ -6365,6 +6372,7 @@ setscope(Param pm)
if (t) {
pm->width = t - refname;
*t = '[';
+ refname = dupstrpfx(refname, pm->width);
}
if (basepm) {
if (basepm->node.flags & PM_NAMEREF) {
@@ -6393,11 +6401,19 @@ setscope(Param pm)
break;
}
}
- } else
+ } else if (!pm->base) {
pm->base = basepm->level;
+ if ((pm->node.flags & PM_UPPER) &&
+ (basepm = upscope(basepm, -(locallevel-1))))
+ pm->base = basepm->level;
+ }
} else if (pm->base < locallevel && refname &&
- (basepm = (Param)getparamnode(realparamtab, refname)))
+ (basepm = (Param)getparamnode(realparamtab, refname))) {
pm->base = basepm->level;
+ if ((pm->node.flags & PM_UPPER) &&
+ (basepm = upscope(basepm, -(locallevel-1))))
+ pm->base = basepm->level;
+ }
if (pm->base > pm->level) {
if (EMULATION(EMULATE_KSH)) {
zerr("%s: global reference cannot refer to local variable",
@@ -6422,7 +6438,7 @@ upscope(Param pm, int reflevel)
{
Param up = pm->old;
while (up && up->level >= reflevel) {
- if (reflevel < 0 && up->level < locallevel)
+ if (reflevel < 0 && up->level < -(reflevel))
break;
pm = up;
up = up->old;