Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: Fix error signaling for reference loops.



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:

Fix error signaling for reference loops
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