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

[PATCH] Don't export hidden parameters



Whenever an -x flagged parameter is updated, the precomputed environment must be updated. However, if the updated -x flagged parameter is hidden by a same name local parameter, then the -x flagged parameter is not supposed to show up in the environment and therefore no environment update should be performed.

There are currently two ways to update hidden parameters. In both cases, the current implementation wrongly updates the precomputed environment with an entry that shouldn't be there.

One way relies on references:

% export VAR=foo
% typeset -n ref=VAR;
% () { local VAR=hide; ref=bar; printenv VAR }
bar

The other one relies on tied parameters:

% export -T VAR=aa:bb var
% () { local -x VAR=foo; var=(cc dd); printenv VAR }
cc

Some combinations of references and tied parameters require additional changes (see tests in the patch).

Don't export hidden parameters

The steps in the GitHub patch exhibit why each change is needed.

Philippe

diff --git a/Src/builtin.c b/Src/builtin.c
index 2e3e5752a..7a19c051a 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2262,14 +2262,14 @@ typeset_single(char *cname, char *pname, Param pm, int func,
 			x = zarrdup(x);
 		    (*pm->gsu.a->setfn)(pm, x);
 		} else if (pm->ename && x)
-		    arrfixenv(pm->ename, x);
+		    arrfixenv(NULL, pm, x);
 	    } else if (PM_TYPE(pm->node.flags) == PM_SCALAR && pm->ename &&
 		       (apm =
 			(Param) paramtab->getnode(paramtab, pm->ename))) {
 		x = (*apm->gsu.a->getfn)(apm);
 		uniqarray(x);
 		if (x)
-		    arrfixenv(pm->node.nam, x);
+		    arrfixenv(pm, NULL, x);
 	    }
 	}
 	if (OPT_ISSET(ops,'p')) {
@@ -2292,7 +2292,8 @@ typeset_single(char *cname, char *pname, Param pm, int func,
 	}
 	if (!(pm->node.flags & (PM_ARRAY|PM_HASHED))) {
 	    if (pm->node.flags & PM_EXPORTED) {
-		if (!(pm->node.flags & PM_UNSET) && !pm->env && !ASG_VALUEP(asg))
+		if (!(pm->node.flags & PM_UNSET) &&
+		    !pm->env && !ASG_VALUEP(asg) && !ishidden(pm))
 		    addenv(pm, getsparam(pname));
 	    } else if (pm->env && !(pm->node.flags & PM_HASHELEM))
 		delenv(pm);
diff --git a/Src/params.c b/Src/params.c
index e111b28c7..700df1c47 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -2838,7 +2838,8 @@ assignstrvalue(Value v, char *val, int flags)
 	  !(isset(ALLEXPORT) && !(v->pm->node.flags & PM_HASHELEM))) ||
 	 (v->pm->node.flags & PM_ARRAY) || v->pm->ename))
 	return;
-    export_param(v->pm);
+    if (!ishidden(v->pm))
+	export_param(v->pm);
 }
 
 /**/
@@ -4027,7 +4028,7 @@ arrsetfn(Param pm, char **x)
 	uniqarray(x);
     /* Arrays tied to colon-arrays may need to fix the environment */
     if (pm->ename && x)
-	arrfixenv(pm->ename, x);
+	arrfixenv(NULL, pm, x);
 }
 
 /* Function to get value of an association parameter */
@@ -4263,7 +4264,7 @@ arrvarsetfn(Param pm, char **x)
 	*dptr = x;
     if (pm->ename) {
 	if (x)
-	    arrfixenv(pm->ename, x);
+	    arrfixenv(NULL, pm, x);
 	else if (*dptr == path)
 	    pathchecked = path;
     }
@@ -4292,7 +4293,7 @@ colonarrsetfn(Param pm, char *x)
 	*dptr = colonsplit(x, pm->node.flags & PM_UNIQUE);
     else
 	*dptr = mkarray(NULL);
-    arrfixenv(pm->node.nam, *dptr);
+    arrfixenv(pm, NULL, *dptr);
     zsfree(x);
 }
 
@@ -4338,7 +4339,7 @@ tiedarrsetfn(Param pm, char *x)
     } else
 	*dptr->arrptr = NULL;
     if (pm->ename)
-	arrfixenv(pm->node.nam, *dptr->arrptr);
+	arrfixenv(pm, NULL, *dptr->arrptr);
 }
 
 /**/
@@ -5276,18 +5277,29 @@ pipestatsetfn(UNUSED(Param pm), char **x)
         numpipestats = 0;
 }
 
+/* Updates the environment string of a tied scalar parameter.
+ *
+ * pm: the tied scalar parameter or NULL
+ * apm: the tied array parameter if pm is NULL or NULL
+ * t: the tied array elements
+ */
+
 /**/
 void
-arrfixenv(char *s, char **t)
+arrfixenv(Param pm, Param apm, char **t)
 {
-    Param pm;
     int joinchar;
 
     if (t == path)
 	cmdnamtab->emptytable(cmdnamtab);
 
-    pm = (Param) paramtab->getnode(paramtab, s);
-    
+
+    if (!pm &&
+	(!(pm = (Param) realparamtab->getnode(realparamtab, apm->ename)) ||
+	 PM_TYPE(pm->node.flags) != PM_SCALAR ||
+	 !pm->ename || strcmp(pm->ename, apm->node.nam)))
+	return;
+
     /*
      * Only one level of a parameter can be exported.  Unless
      * ALLEXPORT is set, this must be global.
@@ -5304,7 +5316,7 @@ arrfixenv(char *s, char **t)
      * Do not "fix" parameters that were not exported
      */
 
-    if (!(pm->node.flags & PM_EXPORTED))
+    if (!(pm->node.flags & PM_EXPORTED) || ishidden(pm))
 	return;
 
     if (pm->node.flags & PM_SPECIAL)
@@ -6464,6 +6476,15 @@ upscope(Param pm, const Param ref)
     return pm;
 }
 
+/* Return whether the parameter is hidden by a same name local paramater. */
+
+/**/
+mod_export int
+ishidden(Param pm)
+{
+    return pm != (Param) realparamtab->getnode2(realparamtab, pm->node.nam);
+}
+
 /**/
 static int
 valid_refname(char *val, int flags)
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 952bbd30c..d49ff1c50 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -2348,4 +2348,51 @@ F:converting from association/array to string should work here too
 >B:16#FF
 >C:16#FF
 
+ show() {
+   printf "%2s: V1=%2s/%2s V2=%2s/%2s\n" \
+     $1 "$V1" "$(printenv V1)" "$V2" "$(printenv V2)"
+ }
+ local V1=A1
+ local -x V2=A2
+ local -n R1=V1 R2=V2
+ show @1
+ () {
+   local V1=B1
+   local -x V2=B2
+   show @2
+   export R1
+   R2=C2
+   show @3
+ }
+ show @4
+ unfunction show
+0:Hidden parameters aren't exported (part 1)
+>@1: V1=A1/   V2=A2/A2
+>@2: V1=B1/   V2=B2/B2
+>@3: V1=B1/   V2=B2/B2
+>@4: V1=A1/A1 V2=C2/C2
+
+ show() {
+   printf "%2s: V1=%-5s/%-5s V2=%-5s/%-5s V3=%-5s/%-5s\n" \
+     $1 "$V1" "$(printenv V1)" "$V2" "$(printenv V2)" "$V3" "$(printenv V3)"
+ }
+ local -x -T V1=A1:1A v1
+ local -x -T V2=A2:2A v2
+ local -n R2=V2 R3=V3
+ local -x -T R3=A3:3A v3
+ show @1
+ () {
+   local -x V1=B1 V2=B2 V3=B3
+   show @2
+   v1=(C1 1C) R2=C2:2C v3=(C3 3C)
+   show @3
+ }
+ show @4
+ unfunction show
+0:Hidden parameters aren't exported (part 2)
+>@1: V1=A1:1A/A1:1A V2=A2:2A/A2:2A V3=A3:3A/A3:3A
+>@2: V1=B1   /B1    V2=B2   /B2    V3=B3   /B3   
+>@3: V1=B1   /B1    V2=B2   /B2    V3=B3   /B3   
+>@4: V1=C1:1C/C1:1C V2=C2:2C/C2:2C V3=C3:3C/C3:3C
+
 %clean


Messages sorted by: Reverse Date, Date, Thread, Author