Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATCH: Fix error signaling for reference loops.
- X-seq: zsh-workers 53798
- From: Philippe Altherr <philippe.altherr@xxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: PATCH: Fix error signaling for reference loops.
- Date: Sat, 21 Jun 2025 11:56:32 +0200
- Archived-at: <https://zsh.org/workers/53798>
- List-id: <zsh-workers.zsh.org>
Reference loops can be created when references to nested variables get relinked after the scope of their nested variable is exited. When a reference of the loop is expanded, the loop is detected but no error is reported. Instead a bogus expansion result is produced.
Example |
typeset -n ref1 typeset -n ref2=ref1; () { typeset ref2=foo ref1=ref2 } echo reached echo $ref1 echo NOT REACHED |
Current output | Expected output |
reached ref1 NOT REACHED | reached test.zsh:8: ref1: invalid self reference |
The following patch fixes the issue:
Unlike with other self reference errors, which are triggered when the reference that closes the loop is defined, no reference is unset; the loop already exists and it's unknown which reference closed the loop.
Philippe
diff --git a/Src/params.c b/Src/params.c
index 6945e73e9..89fa707fd 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -6278,19 +6278,19 @@ resolve_nameref(Param pm, const Asgment stop)
if (pm && (pm->node.flags & PM_NAMEREF)) {
char *refname = GETREFNAME(pm);
- if (pm->node.flags & (PM_UNSET|PM_TAGGED)) {
+ if (pm->node.flags & PM_TAGGED) {
+ zerr("%s: invalid self reference", pm->node.nam);
+ return NULL;
+ } else if (pm->node.flags & PM_UNSET) {
/* Semaphore with createparam() */
pm->node.flags &= ~PM_UNSET;
if (pm->node.flags & PM_NEWREF) /* See setloopvar() */
return NULL;
- if (refname && *refname && (pm->node.flags & PM_TAGGED))
- pm->node.flags |= PM_SELFREF; /* See setscope() */
return (HashNode) pm;
} else if (refname) {
- if ((pm->node.flags & PM_TAGGED) ||
- (stop && strcmp(refname, stop->name) == 0)) {
+ if (stop && strcmp(refname, stop->name) == 0) {
/* zwarnnam(refname, "invalid self reference"); */
- return stop ? (HashNode)pm : NULL;
+ return (HashNode)pm;
}
if (*refname)
seek = refname;
@@ -6420,15 +6420,7 @@ setscope(Param pm)
if (basepm) {
if (basepm->node.flags & PM_NAMEREF) {
if (pm == basepm) {
- if (pm->node.flags & PM_SELFREF) {
- /* Loop signalled by resolve_nameref() */
- if (upscope(pm, pm->base) == pm) {
- zerr("%s: invalid self reference", refname);
- unsetparam_pm(pm, 0, 1);
- break;
- }
- pm->node.flags &= ~PM_SELFREF;
- } else if (pm->base == pm->level) {
+ if (pm->base == pm->level) {
if (refname && *refname &&
strcmp(pm->node.nam, refname) == 0) {
zerr("%s: invalid self reference", refname);
diff --git a/Src/zsh.h b/Src/zsh.h
index 4e5c02980..ebb63f498 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1935,7 +1935,6 @@ struct tieddata {
#define PM_NAMEDDIR (1<<29) /* has a corresponding nameddirtab entry */
#define PM_NAMEREF (1<<30) /* pointer to a different parameter */
-#define PM_SELFREF PM_UNIQUE /* Overload when namerefs resolved */
#define PM_NEWREF PM_SINGLE /* Overload in for-loop namerefs */
/* The option string corresponds to the first of the variables above */
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 7ba97f5a6..33d05a353 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -1291,4 +1291,43 @@ F:previously this could create an infinite recursion and crash
>ref1=var2
>ref2=var2
+ typeset -n ref1
+ typeset -n ref2=ref1;
+ () {
+ typeset ref2=foo
+ ref1=ref2
+ }
+ echo reached
+ echo $ref1
+ echo NOT REACHED
+1:expansion of incidental reference loop triggers error
+>reached
+*?*: ref1: invalid self reference
+
+ typeset -n ref1
+ typeset -n ref2=ref1;
+ () {
+ typeset ref2=foo
+ ref1=ref2
+ }
+ echo reached
+ ref1=foo
+ echo NOT REACHED
+1:assignment to incidental reference loop triggers error
+>reached
+*?*: ref1: invalid self reference
+
+ typeset -n ref1
+ typeset -n ref2=ref1;
+ () {
+ typeset ref2=foo
+ ref1=ref2
+ }
+ echo reached
+ typeset -n ref3=ref1
+ echo NOT REACHED
+1:reference to incidental reference loop triggers error
+>reached
+*?*: ref1: invalid self reference
+
%clean
Messages sorted by:
Reverse Date,
Date,
Thread,
Author