Kamil Dudka bde7c9
From 932bb5a32c7b9a477c5209e62363920efdbc71d1 Mon Sep 17 00:00:00 2001
Kamil Dudka bde7c9
From: Peter Stephenson <pws@zsh.org>
Kamil Dudka bde7c9
Date: Fri, 29 Sep 2017 16:46:01 +0100
Kamil Dudka bde7c9
Subject: [PATCH 1/2] 41787 (plus minor tweaks): use $FUNCSTACK for function
Kamil Dudka bde7c9
 nesting depth.
Kamil Dudka bde7c9
Kamil Dudka bde7c9
Initialised from existing configuration value.
Kamil Dudka bde7c9
Kamil Dudka bde7c9
Upstream-commit: 174e560a23e40725cd0b50669a52d831342e5246
Kamil Dudka bde7c9
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka bde7c9
---
Kamil Dudka bde7c9
 Doc/Zsh/params.yo    | 10 ++++++++++
Kamil Dudka bde7c9
 Doc/zshparam.1       |  9 +++++++++
Kamil Dudka bde7c9
 README               | 26 +++++++++++++++++++++++++-
Kamil Dudka bde7c9
 Src/exec.c           | 17 ++++++-----------
Kamil Dudka bde7c9
 Src/params.c         | 14 ++++++++++++++
Kamil Dudka bde7c9
 Test/C04funcdef.ztst |  8 ++++++++
Kamil Dudka bde7c9
 configure.ac         |  6 +++---
Kamil Dudka bde7c9
 7 files changed, 75 insertions(+), 15 deletions(-)
Kamil Dudka bde7c9
Kamil Dudka bde7c9
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
Kamil Dudka bde7c9
index 817496b..26d5039 100644
Kamil Dudka bde7c9
--- a/Doc/Zsh/params.yo
Kamil Dudka bde7c9
+++ b/Doc/Zsh/params.yo
Kamil Dudka bde7c9
@@ -668,6 +668,16 @@ This value is system dependent and is intended for debugging
Kamil Dudka bde7c9
 purposes.  It is also useful with the tt(zsh/system) module which
Kamil Dudka bde7c9
 allows the number to be turned into a name or message.
Kamil Dudka bde7c9
 )
Kamil Dudka bde7c9
+vindex(FUNCNEST)
Kamil Dudka bde7c9
+item(tt(FUNCNEST) <S>)(
Kamil Dudka bde7c9
+Integer.  If greater than or equal to zero, the maximum nesting depth of
Kamil Dudka bde7c9
+shell functions.  When it is exceeded, an error is raised at the point
Kamil Dudka bde7c9
+where a function is called.  The default value is determined when
Kamil Dudka bde7c9
+the shell is configured, but is typically 500.  Increasing
Kamil Dudka bde7c9
+the value increases the danger of a runaway function recursion
Kamil Dudka bde7c9
+causing the shell to crash.  Setting a negative value turns off
Kamil Dudka bde7c9
+the check.
Kamil Dudka bde7c9
+)
Kamil Dudka bde7c9
 vindex(GID)
Kamil Dudka bde7c9
 item(tt(GID) <S>)(
Kamil Dudka bde7c9
 The real group ID of the shell process.  If you have sufficient privileges,
Kamil Dudka bde7c9
diff --git a/Doc/zshparam.1 b/Doc/zshparam.1
Kamil Dudka bde7c9
index 44d8629..c7188cb 100644
Kamil Dudka bde7c9
--- a/Doc/zshparam.1
Kamil Dudka bde7c9
+++ b/Doc/zshparam.1
Kamil Dudka bde7c9
@@ -701,6 +701,15 @@ This value is system dependent and is intended for debugging
Kamil Dudka bde7c9
 purposes\&.  It is also useful with the \fBzsh/system\fP module which
Kamil Dudka bde7c9
 allows the number to be turned into a name or message\&.
Kamil Dudka bde7c9
 .TP
Kamil Dudka bde7c9
+\fBFUNCNEST\fP <S>
Kamil Dudka bde7c9
+Integer\&.  If greater than or equal to zero, the maximum nesting depth of
Kamil Dudka bde7c9
+shell functions\&.  When it is exceeded, an error is raised at the point
Kamil Dudka bde7c9
+where a function is called\&.  The default value is determined when
Kamil Dudka bde7c9
+the shell is configured, but is typically 500\&.  Increasing
Kamil Dudka bde7c9
+the value increases the danger of a runaway function recursion
Kamil Dudka bde7c9
+causing the shell to crash\&.  Setting a negative value turns off
Kamil Dudka bde7c9
+the check\&.
Kamil Dudka bde7c9
+.TP
Kamil Dudka bde7c9
 \fBGID\fP <S>
Kamil Dudka bde7c9
 The real group ID of the shell process\&.  If you have sufficient privileges,
Kamil Dudka bde7c9
 you may change the group ID of the shell process by assigning to this
Kamil Dudka bde7c9
diff --git a/README b/README
Kamil Dudka bde7c9
index e22cfc1..b5c0769 100644
Kamil Dudka bde7c9
--- a/README
Kamil Dudka bde7c9
+++ b/README
Kamil Dudka bde7c9
@@ -30,9 +30,33 @@ Zsh is a shell with lots of features.  For a list of some of these, see the
Kamil Dudka bde7c9
 file FEATURES, and for the latest changes see NEWS.  For more
Kamil Dudka bde7c9
 details, see the documentation.
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
-Incompatibilities since 5.3.1
Kamil Dudka bde7c9
+Incompatibilities since 5.4.2
Kamil Dudka bde7c9
 -----------------------------
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
+1) The default build-time maximum nested function depth has been
Kamil Dudka bde7c9
+decreased from 1000 to 500 based on user experience.  However,
Kamil Dudka bde7c9
+it can now be changed at run time via the variable FUNCNEST.
Kamil Dudka bde7c9
+If you previously configured the shell to set a different value,
Kamil Dudka bde7c9
+or to remove the check, this is now reflected in the default
Kamil Dudka bde7c9
+value of the variable.
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
+2) The syntax
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
+foo=([key]=value)
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
+can be used to set elements of arrays and associative arrays.  In the
Kamil Dudka bde7c9
+unlikely event that you need to set an array by matching files using a
Kamil Dudka bde7c9
+pattern that starts with a character range followed by '=', you need to
Kamil Dudka bde7c9
+quote the '=', e.g.:
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
+foo=([aeiou]\=vowel)
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
+This is only required for array values contained within parentheses;
Kamil Dudka bde7c9
+command line expansion for normal arguments has not changed.
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
+Incompatibilities between 5.3.1 and 5.4.2
Kamil Dudka bde7c9
+-----------------------------------------
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
 1) The default behaviour of code like the following has changed:
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
   alias foo='noglob foo'
Kamil Dudka bde7c9
diff --git a/Src/exec.c b/Src/exec.c
Kamil Dudka bde7c9
index cd99733..0f2bb4a 100644
Kamil Dudka bde7c9
--- a/Src/exec.c
Kamil Dudka bde7c9
+++ b/Src/exec.c
Kamil Dudka bde7c9
@@ -5475,9 +5475,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
     struct funcstack fstack;
Kamil Dudka bde7c9
     static int oflags;
Kamil Dudka bde7c9
     Emulation_options save_sticky = NULL;
Kamil Dudka bde7c9
-#ifdef MAX_FUNCTION_DEPTH
Kamil Dudka bde7c9
     static int funcdepth;
Kamil Dudka bde7c9
-#endif
Kamil Dudka bde7c9
     Heap funcheap;
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
     queue_signals();	/* Lots of memory and global state changes coming */
Kamil Dudka bde7c9
@@ -5607,13 +5605,12 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 		argzero = ztrdup(argzero);
Kamil Dudka bde7c9
 	    }
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
-#ifdef MAX_FUNCTION_DEPTH
Kamil Dudka bde7c9
-	if(++funcdepth > MAX_FUNCTION_DEPTH)
Kamil Dudka bde7c9
-	    {
Kamil Dudka bde7c9
-		zerr("maximum nested function level reached");
Kamil Dudka bde7c9
-		goto undoshfunc;
Kamil Dudka bde7c9
-	    }
Kamil Dudka bde7c9
-#endif
Kamil Dudka bde7c9
+	++funcdepth;
Kamil Dudka bde7c9
+	if (zsh_funcnest >= 0 && funcdepth > zsh_funcnest) {
Kamil Dudka bde7c9
+	    zerr("maximum nested function level reached; increase FUNCNEST?");
Kamil Dudka bde7c9
+	    lastval = 1;
Kamil Dudka bde7c9
+	    goto undoshfunc;
Kamil Dudka bde7c9
+	}
Kamil Dudka bde7c9
 	fstack.name = dupstring(name);
Kamil Dudka bde7c9
 	/*
Kamil Dudka bde7c9
 	 * The caller is whatever is immediately before on the stack,
Kamil Dudka bde7c9
@@ -5652,10 +5649,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	runshfunc(prog, wrappers, fstack.name);
Kamil Dudka bde7c9
     doneshfunc:
Kamil Dudka bde7c9
 	funcstack = fstack.prev;
Kamil Dudka bde7c9
-#ifdef MAX_FUNCTION_DEPTH
Kamil Dudka bde7c9
     undoshfunc:
Kamil Dudka bde7c9
 	--funcdepth;
Kamil Dudka bde7c9
-#endif
Kamil Dudka bde7c9
 	if (retflag) {
Kamil Dudka bde7c9
 	    retflag = 0;
Kamil Dudka bde7c9
 	    breaks = obreaks;
Kamil Dudka bde7c9
diff --git a/Src/params.c b/Src/params.c
Kamil Dudka bde7c9
index 6fbee88..9c7833f 100644
Kamil Dudka bde7c9
--- a/Src/params.c
Kamil Dudka bde7c9
+++ b/Src/params.c
Kamil Dudka bde7c9
@@ -101,6 +101,19 @@ zlong lastval,		/* $?           */
Kamil Dudka bde7c9
      rprompt_indent,	/* $ZLE_RPROMPT_INDENT */
Kamil Dudka bde7c9
      ppid,		/* $PPID        */
Kamil Dudka bde7c9
      zsh_subshell;	/* $ZSH_SUBSHELL */
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
+/* $FUNCNEST    */
Kamil Dudka bde7c9
+/**/
Kamil Dudka bde7c9
+mod_export
Kamil Dudka bde7c9
+zlong zsh_funcnest =
Kamil Dudka bde7c9
+#ifdef MAX_FUNCTION_DEPTH
Kamil Dudka bde7c9
+    MAX_FUNCTION_DEPTH
Kamil Dudka bde7c9
+#else
Kamil Dudka bde7c9
+    /* Disabled by default but can be enabled at run time */
Kamil Dudka bde7c9
+    -1
Kamil Dudka bde7c9
+#endif
Kamil Dudka bde7c9
+    ;
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
 /**/
Kamil Dudka bde7c9
 zlong lineno,		/* $LINENO      */
Kamil Dudka bde7c9
      zoptind,		/* $OPTIND      */
Kamil Dudka bde7c9
@@ -337,6 +350,7 @@ IPDEF5("COLUMNS", &zterm_columns, zlevar_gsu),
Kamil Dudka bde7c9
 IPDEF5("LINES", &zterm_lines, zlevar_gsu),
Kamil Dudka bde7c9
 IPDEF5U("ZLE_RPROMPT_INDENT", &rprompt_indent, rprompt_indent_gsu),
Kamil Dudka bde7c9
 IPDEF5("SHLVL", &shlvl, varinteger_gsu),
Kamil Dudka bde7c9
+IPDEF5("FUNCNEST", &zsh_funcnest, varinteger_gsu),
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 /* Don't import internal integer status variables. */
Kamil Dudka bde7c9
 #define IPDEF6(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(F),10,0,NULL,NULL,NULL,0}
Kamil Dudka bde7c9
diff --git a/Test/C04funcdef.ztst b/Test/C04funcdef.ztst
Kamil Dudka bde7c9
index 6a675e0..0c00a04 100644
Kamil Dudka bde7c9
--- a/Test/C04funcdef.ztst
Kamil Dudka bde7c9
+++ b/Test/C04funcdef.ztst
Kamil Dudka bde7c9
@@ -515,6 +515,14 @@
Kamil Dudka bde7c9
 0:autoload with absolute path not cancelled by bare autoload
Kamil Dudka bde7c9
 >I have been loaded by explicit path.
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
+  (
Kamil Dudka bde7c9
+    FUNCNEST=0
Kamil Dudka bde7c9
+    fn() { true; }
Kamil Dudka bde7c9
+    fn
Kamil Dudka bde7c9
+  )
Kamil Dudka bde7c9
+1:
Kamil Dudka bde7c9
+?fn:4: maximum nested function level reached; increase FUNCNEST?
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
 %clean
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
  rm -f file.in file.out
Kamil Dudka bde7c9
diff --git a/configure.ac b/configure.ac
Kamil Dudka bde7c9
index ec0bdae..1a498f8 100644
Kamil Dudka bde7c9
--- a/configure.ac
Kamil Dudka bde7c9
+++ b/configure.ac
Kamil Dudka bde7c9
@@ -415,13 +415,13 @@ ifdef([max_function_depth],[undefine([max_function_depth])])dnl
Kamil Dudka bde7c9
 AH_TEMPLATE([MAX_FUNCTION_DEPTH],
Kamil Dudka bde7c9
 [Define for function depth limits])
Kamil Dudka bde7c9
 AC_ARG_ENABLE(max-function-depth,
Kamil Dudka bde7c9
-AC_HELP_STRING([--enable-max-function-depth=MAX], [limit function depth to MAX, default 1000]),
Kamil Dudka bde7c9
+AC_HELP_STRING([--enable-max-function-depth=MAX], [limit function depth to MAX, default 500]),
Kamil Dudka bde7c9
 [if test x$enableval = xyes; then
Kamil Dudka bde7c9
-  AC_DEFINE(MAX_FUNCTION_DEPTH, 1000)
Kamil Dudka bde7c9
+  AC_DEFINE(MAX_FUNCTION_DEPTH, 500)
Kamil Dudka bde7c9
 elif test x$enableval != xno; then
Kamil Dudka bde7c9
   AC_DEFINE_UNQUOTED(MAX_FUNCTION_DEPTH, $enableval)
Kamil Dudka bde7c9
 fi],
Kamil Dudka bde7c9
-[AC_DEFINE(MAX_FUNCTION_DEPTH, 1000)]
Kamil Dudka bde7c9
+[AC_DEFINE(MAX_FUNCTION_DEPTH, 500)]
Kamil Dudka bde7c9
 )
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 ifdef([default_readnullcmd],[undefine([default_readnullcmd])])dnl
Kamil Dudka bde7c9
-- 
Kamil Dudka bde7c9
2.13.6
Kamil Dudka bde7c9
Kamil Dudka bde7c9
Kamil Dudka bde7c9
From aee6a617b5769ee6224165560db43bb8b8ee64ba Mon Sep 17 00:00:00 2001
Kamil Dudka bde7c9
From: Peter Stephenson <pws@zsh.org>
Kamil Dudka bde7c9
Date: Wed, 4 Oct 2017 09:18:51 +0100
Kamil Dudka bde7c9
Subject: [PATCH 2/2] 41802 (minor tweaks): use heap during shell function
Kamil Dudka bde7c9
 call.
Kamil Dudka bde7c9
Kamil Dudka bde7c9
Replaces stack for more efficient memory management.
Kamil Dudka bde7c9
Kamil Dudka bde7c9
Also fix debug message when FUNCNEST is increased.
Kamil Dudka bde7c9
Kamil Dudka bde7c9
Upstream-commit: e573857a033504f7918c4a2309151329820f115f
Kamil Dudka bde7c9
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
Kamil Dudka bde7c9
---
Kamil Dudka bde7c9
 Src/exec.c  | 154 +++++++++++++++++++++++++++++++++---------------------------
Kamil Dudka bde7c9
 Src/parse.c |   3 +-
Kamil Dudka bde7c9
 2 files changed, 87 insertions(+), 70 deletions(-)
Kamil Dudka bde7c9
Kamil Dudka bde7c9
diff --git a/Src/exec.c b/Src/exec.c
Kamil Dudka bde7c9
index 0f2bb4a..db77303 100644
Kamil Dudka bde7c9
--- a/Src/exec.c
Kamil Dudka bde7c9
+++ b/Src/exec.c
Kamil Dudka bde7c9
@@ -41,6 +41,20 @@ enum {
Kamil Dudka bde7c9
     ADDVAR_RESTORE =  1 << 2
Kamil Dudka bde7c9
 };
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
+/* Structure in which to save values around shell function call */
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
+struct funcsave {
Kamil Dudka bde7c9
+    char opts[OPT_SIZE];
Kamil Dudka bde7c9
+    char *argv0;
Kamil Dudka bde7c9
+    int zoptind, lastval, optcind, numpipestats;
Kamil Dudka bde7c9
+    int *pipestats;
Kamil Dudka bde7c9
+    char *scriptname;
Kamil Dudka bde7c9
+    int breaks, contflag, loops, emulation, noerrexit, oflags, restore_sticky;
Kamil Dudka bde7c9
+    Emulation_options sticky;
Kamil Dudka bde7c9
+    struct funcstack fstack;
Kamil Dudka bde7c9
+};
Kamil Dudka bde7c9
+typedef struct funcsave *Funcsave;
Kamil Dudka bde7c9
+
Kamil Dudka bde7c9
 /*
Kamil Dudka bde7c9
  * used to suppress ERREXIT and trapping of SIGZERR, SIGEXIT.
Kamil Dudka bde7c9
  * Bits from noerrexit_bits.
Kamil Dudka bde7c9
@@ -5462,34 +5476,36 @@ int sticky_emulation_differs(Emulation_options sticky2)
Kamil Dudka bde7c9
 mod_export int
Kamil Dudka bde7c9
 doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 {
Kamil Dudka bde7c9
-    char **pptab, **x, *oargv0;
Kamil Dudka bde7c9
-    int oldzoptind, oldlastval, oldoptcind, oldnumpipestats, ret;
Kamil Dudka bde7c9
-    int *oldpipestats = NULL;
Kamil Dudka bde7c9
-    char saveopts[OPT_SIZE], *oldscriptname = scriptname;
Kamil Dudka bde7c9
+    char **pptab, **x;
Kamil Dudka bde7c9
+    int ret;
Kamil Dudka bde7c9
     char *name = shfunc->node.nam;
Kamil Dudka bde7c9
-    int flags = shfunc->node.flags, ooflags;
Kamil Dudka bde7c9
-    int savnoerrexit;
Kamil Dudka bde7c9
+    int flags = shfunc->node.flags;
Kamil Dudka bde7c9
     char *fname = dupstring(name);
Kamil Dudka bde7c9
-    int obreaks, ocontflag, oloops, saveemulation, restore_sticky;
Kamil Dudka bde7c9
     Eprog prog;
Kamil Dudka bde7c9
-    struct funcstack fstack;
Kamil Dudka bde7c9
     static int oflags;
Kamil Dudka bde7c9
-    Emulation_options save_sticky = NULL;
Kamil Dudka bde7c9
     static int funcdepth;
Kamil Dudka bde7c9
     Heap funcheap;
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
     queue_signals();	/* Lots of memory and global state changes coming */
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
     NEWHEAPS(funcheap) {
Kamil Dudka bde7c9
-	oargv0 = NULL;
Kamil Dudka bde7c9
-	obreaks = breaks;
Kamil Dudka bde7c9
-	ocontflag = contflag;
Kamil Dudka bde7c9
-	oloops = loops;
Kamil Dudka bde7c9
+	/*
Kamil Dudka bde7c9
+	 * Save data in heap rather than on stack to keep recursive
Kamil Dudka bde7c9
+	 * function cost down --- use of heap memory should be efficient
Kamil Dudka bde7c9
+	 * at this point.  Saving is not actually massive.
Kamil Dudka bde7c9
+	 */
Kamil Dudka bde7c9
+	Funcsave funcsave = zhalloc(sizeof(struct funcsave));
Kamil Dudka bde7c9
+	funcsave->scriptname = scriptname;
Kamil Dudka bde7c9
+	funcsave->argv0 = NULL;
Kamil Dudka bde7c9
+	funcsave->breaks = breaks;
Kamil Dudka bde7c9
+	funcsave->contflag = contflag;
Kamil Dudka bde7c9
+	funcsave->loops = loops;
Kamil Dudka bde7c9
+	funcsave->lastval = lastval;
Kamil Dudka bde7c9
+	funcsave->pipestats = NULL;
Kamil Dudka bde7c9
+	funcsave->numpipestats = numpipestats;
Kamil Dudka bde7c9
+	funcsave->noerrexit = noerrexit;
Kamil Dudka bde7c9
 	if (trap_state == TRAP_STATE_PRIMED)
Kamil Dudka bde7c9
 	    trap_return--;
Kamil Dudka bde7c9
-	oldlastval = lastval;
Kamil Dudka bde7c9
-	oldnumpipestats = numpipestats;
Kamil Dudka bde7c9
-	savnoerrexit = noerrexit;
Kamil Dudka bde7c9
 	/*
Kamil Dudka bde7c9
 	 * Suppression of ERR_RETURN is turned off in function scope.
Kamil Dudka bde7c9
 	 */
Kamil Dudka bde7c9
@@ -5500,8 +5516,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	     * immediately by a pushheap/popheap pair.
Kamil Dudka bde7c9
 	     */
Kamil Dudka bde7c9
 	    size_t bytes = sizeof(int)*numpipestats;
Kamil Dudka bde7c9
-	    oldpipestats = (int *)zhalloc(bytes);
Kamil Dudka bde7c9
-	    memcpy(oldpipestats, pipestats, bytes);
Kamil Dudka bde7c9
+	    funcsave->pipestats = (int *)zhalloc(bytes);
Kamil Dudka bde7c9
+	    memcpy(funcsave->pipestats, pipestats, bytes);
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 	starttrapscope();
Kamil Dudka bde7c9
@@ -5510,8 +5526,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	pptab = pparams;
Kamil Dudka bde7c9
 	if (!(flags & PM_UNDEFINED))
Kamil Dudka bde7c9
 	    scriptname = dupstring(name);
Kamil Dudka bde7c9
-	oldzoptind = zoptind;
Kamil Dudka bde7c9
-	oldoptcind = optcind;
Kamil Dudka bde7c9
+	funcsave->zoptind = zoptind;
Kamil Dudka bde7c9
+	funcsave->optcind = optcind;
Kamil Dudka bde7c9
 	if (!isset(POSIXBUILTINS)) {
Kamil Dudka bde7c9
 	    zoptind = 1;
Kamil Dudka bde7c9
 	    optcind = 0;
Kamil Dudka bde7c9
@@ -5520,9 +5536,9 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	/* We need to save the current options even if LOCALOPTIONS is *
Kamil Dudka bde7c9
 	 * not currently set.  That's because if it gets set in the    *
Kamil Dudka bde7c9
 	 * function we need to restore the original options on exit.   */
Kamil Dudka bde7c9
-	memcpy(saveopts, opts, sizeof(opts));
Kamil Dudka bde7c9
-	saveemulation = emulation;
Kamil Dudka bde7c9
-	save_sticky = sticky;
Kamil Dudka bde7c9
+	memcpy(funcsave->opts, opts, sizeof(opts));
Kamil Dudka bde7c9
+	funcsave->emulation = emulation;
Kamil Dudka bde7c9
+	funcsave->sticky = sticky;
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 	if (sticky_emulation_differs(shfunc->sticky)) {
Kamil Dudka bde7c9
 	    /*
Kamil Dudka bde7c9
@@ -5539,7 +5555,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	     */
Kamil Dudka bde7c9
 	    sticky = sticky_emulation_dup(shfunc->sticky, 1);
Kamil Dudka bde7c9
 	    emulation = sticky->emulation;
Kamil Dudka bde7c9
-	    restore_sticky = 1;
Kamil Dudka bde7c9
+	    funcsave->restore_sticky = 1;
Kamil Dudka bde7c9
 	    installemulation(emulation, opts);
Kamil Dudka bde7c9
 	    if (sticky->n_on_opts) {
Kamil Dudka bde7c9
 		OptIndex *onptr;
Kamil Dudka bde7c9
@@ -5558,7 +5574,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	    /* All emulations start with pattern disables clear */
Kamil Dudka bde7c9
 	    clearpatterndisables();
Kamil Dudka bde7c9
 	} else
Kamil Dudka bde7c9
-	    restore_sticky = 0;
Kamil Dudka bde7c9
+	    funcsave->restore_sticky = 0;
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 	if (flags & (PM_TAGGED|PM_TAGGED_LOCAL))
Kamil Dudka bde7c9
 	    opts[XTRACE] = 1;
Kamil Dudka bde7c9
@@ -5576,11 +5592,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	    else
Kamil Dudka bde7c9
 		opts[WARNNESTEDVAR] = 0;
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
-	ooflags = oflags;
Kamil Dudka bde7c9
+	funcsave->oflags = oflags;
Kamil Dudka bde7c9
 	/*
Kamil Dudka bde7c9
 	 * oflags is static, because we compare it on the next recursive
Kamil Dudka bde7c9
-	 * call.  Hence also we maintain ooflags for restoring the previous
Kamil Dudka bde7c9
-	 * value of oflags after the call.
Kamil Dudka bde7c9
+	 * call.  Hence also we maintain a saved version for restoring
Kamil Dudka bde7c9
+	 * the previous value of oflags after the call.
Kamil Dudka bde7c9
 	 */
Kamil Dudka bde7c9
 	oflags = flags;
Kamil Dudka bde7c9
 	opts[PRINTEXITVALUE] = 0;
Kamil Dudka bde7c9
@@ -5591,7 +5607,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	    pparams = x = (char **) zshcalloc(((sizeof *x) *
Kamil Dudka bde7c9
 					       (1 + countlinknodes(doshargs))));
Kamil Dudka bde7c9
 	    if (isset(FUNCTIONARGZERO)) {
Kamil Dudka bde7c9
-		oargv0 = argzero;
Kamil Dudka bde7c9
+		funcsave->argv0 = argzero;
Kamil Dudka bde7c9
 		argzero = ztrdup(getdata(node));
Kamil Dudka bde7c9
 	    }
Kamil Dudka bde7c9
 	    /* first node contains name regardless of option */
Kamil Dudka bde7c9
@@ -5601,7 +5617,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	} else {
Kamil Dudka bde7c9
 	    pparams = (char **) zshcalloc(sizeof *pparams);
Kamil Dudka bde7c9
 	    if (isset(FUNCTIONARGZERO)) {
Kamil Dudka bde7c9
-		oargv0 = argzero;
Kamil Dudka bde7c9
+		funcsave->argv0 = argzero;
Kamil Dudka bde7c9
 		argzero = ztrdup(argzero);
Kamil Dudka bde7c9
 	    }
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
@@ -5611,21 +5627,21 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	    lastval = 1;
Kamil Dudka bde7c9
 	    goto undoshfunc;
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
-	fstack.name = dupstring(name);
Kamil Dudka bde7c9
+	funcsave->fstack.name = dupstring(name);
Kamil Dudka bde7c9
 	/*
Kamil Dudka bde7c9
 	 * The caller is whatever is immediately before on the stack,
Kamil Dudka bde7c9
 	 * unless we're at the top, in which case it's the script
Kamil Dudka bde7c9
 	 * or interactive shell name.
Kamil Dudka bde7c9
 	 */
Kamil Dudka bde7c9
-	fstack.caller = funcstack ? funcstack->name :
Kamil Dudka bde7c9
-	    dupstring(oargv0 ? oargv0 : argzero);
Kamil Dudka bde7c9
-	fstack.lineno = lineno;
Kamil Dudka bde7c9
-	fstack.prev = funcstack;
Kamil Dudka bde7c9
-	fstack.tp = FS_FUNC;
Kamil Dudka bde7c9
-	funcstack = &fstack;
Kamil Dudka bde7c9
+	funcsave->fstack.caller = funcstack ? funcstack->name :
Kamil Dudka bde7c9
+	    dupstring(funcsave->argv0 ? funcsave->argv0 : argzero);
Kamil Dudka bde7c9
+	funcsave->fstack.lineno = lineno;
Kamil Dudka bde7c9
+	funcsave->fstack.prev = funcstack;
Kamil Dudka bde7c9
+	funcsave->fstack.tp = FS_FUNC;
Kamil Dudka bde7c9
+	funcstack = &funcsave->fstack;
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
-	fstack.flineno = shfunc->lineno;
Kamil Dudka bde7c9
-	fstack.filename = getshfuncfile(shfunc);
Kamil Dudka bde7c9
+	funcsave->fstack.flineno = shfunc->lineno;
Kamil Dudka bde7c9
+	funcsave->fstack.filename = getshfuncfile(shfunc);
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 	prog = shfunc->funcdef;
Kamil Dudka bde7c9
 	if (prog->flags & EF_RUN) {
Kamil Dudka bde7c9
@@ -5633,7 +5649,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 	    prog->flags &= ~EF_RUN;
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
-	    runshfunc(prog, NULL, fstack.name);
Kamil Dudka bde7c9
+	    runshfunc(prog, NULL, funcsave->fstack.name);
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 	    if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
Kamil Dudka bde7c9
 						    (name = fname)))) {
Kamil Dudka bde7c9
@@ -5646,52 +5662,52 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	    }
Kamil Dudka bde7c9
 	    prog = shf->funcdef;
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
-	runshfunc(prog, wrappers, fstack.name);
Kamil Dudka bde7c9
+	runshfunc(prog, wrappers, funcsave->fstack.name);
Kamil Dudka bde7c9
     doneshfunc:
Kamil Dudka bde7c9
-	funcstack = fstack.prev;
Kamil Dudka bde7c9
+	funcstack = funcsave->fstack.prev;
Kamil Dudka bde7c9
     undoshfunc:
Kamil Dudka bde7c9
 	--funcdepth;
Kamil Dudka bde7c9
 	if (retflag) {
Kamil Dudka bde7c9
 	    retflag = 0;
Kamil Dudka bde7c9
-	    breaks = obreaks;
Kamil Dudka bde7c9
+	    breaks = funcsave->breaks;
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
 	freearray(pparams);
Kamil Dudka bde7c9
-	if (oargv0) {
Kamil Dudka bde7c9
+	if (funcsave->argv0) {
Kamil Dudka bde7c9
 	    zsfree(argzero);
Kamil Dudka bde7c9
-	    argzero = oargv0;
Kamil Dudka bde7c9
+	    argzero = funcsave->argv0;
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
 	pparams = pptab;
Kamil Dudka bde7c9
 	if (!isset(POSIXBUILTINS)) {
Kamil Dudka bde7c9
-	    zoptind = oldzoptind;
Kamil Dudka bde7c9
-	    optcind = oldoptcind;
Kamil Dudka bde7c9
+	    zoptind = funcsave->zoptind;
Kamil Dudka bde7c9
+	    optcind = funcsave->optcind;
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
-	scriptname = oldscriptname;
Kamil Dudka bde7c9
-	oflags = ooflags;
Kamil Dudka bde7c9
+	scriptname = funcsave->scriptname;
Kamil Dudka bde7c9
+	oflags = funcsave->oflags;
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 	endpatternscope();	/* before restoring old LOCALPATTERNS */
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
-	if (restore_sticky) {
Kamil Dudka bde7c9
+	if (funcsave->restore_sticky) {
Kamil Dudka bde7c9
 	    /*
Kamil Dudka bde7c9
 	     * If we switched to an emulation environment just for
Kamil Dudka bde7c9
 	     * this function, we interpret the option and emulation
Kamil Dudka bde7c9
 	     * switch as being a firewall between environments.
Kamil Dudka bde7c9
 	     */
Kamil Dudka bde7c9
-	    memcpy(opts, saveopts, sizeof(opts));
Kamil Dudka bde7c9
-	    emulation = saveemulation;
Kamil Dudka bde7c9
-	    sticky = save_sticky;
Kamil Dudka bde7c9
+	    memcpy(opts, funcsave->opts, sizeof(opts));
Kamil Dudka bde7c9
+	    emulation = funcsave->emulation;
Kamil Dudka bde7c9
+	    sticky = funcsave->sticky;
Kamil Dudka bde7c9
 	} else if (isset(LOCALOPTIONS)) {
Kamil Dudka bde7c9
 	    /* restore all shell options except PRIVILEGED and RESTRICTED */
Kamil Dudka bde7c9
-	    saveopts[PRIVILEGED] = opts[PRIVILEGED];
Kamil Dudka bde7c9
-	    saveopts[RESTRICTED] = opts[RESTRICTED];
Kamil Dudka bde7c9
-	    memcpy(opts, saveopts, sizeof(opts));
Kamil Dudka bde7c9
-	    emulation = saveemulation;
Kamil Dudka bde7c9
+	    funcsave->opts[PRIVILEGED] = opts[PRIVILEGED];
Kamil Dudka bde7c9
+	    funcsave->opts[RESTRICTED] = opts[RESTRICTED];
Kamil Dudka bde7c9
+	    memcpy(opts, funcsave->opts, sizeof(opts));
Kamil Dudka bde7c9
+	    emulation = funcsave->emulation;
Kamil Dudka bde7c9
 	} else {
Kamil Dudka bde7c9
 	    /* just restore a couple. */
Kamil Dudka bde7c9
-	    opts[XTRACE] = saveopts[XTRACE];
Kamil Dudka bde7c9
-	    opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
Kamil Dudka bde7c9
-	    opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
Kamil Dudka bde7c9
-	    opts[LOCALLOOPS] = saveopts[LOCALLOOPS];
Kamil Dudka bde7c9
-	    opts[WARNNESTEDVAR] = saveopts[WARNNESTEDVAR];
Kamil Dudka bde7c9
+	    opts[XTRACE] = funcsave->opts[XTRACE];
Kamil Dudka bde7c9
+	    opts[PRINTEXITVALUE] = funcsave->opts[PRINTEXITVALUE];
Kamil Dudka bde7c9
+	    opts[LOCALOPTIONS] = funcsave->opts[LOCALOPTIONS];
Kamil Dudka bde7c9
+	    opts[LOCALLOOPS] = funcsave->opts[LOCALLOOPS];
Kamil Dudka bde7c9
+	    opts[WARNNESTEDVAR] = funcsave->opts[WARNNESTEDVAR];
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 	if (opts[LOCALLOOPS]) {
Kamil Dudka bde7c9
@@ -5699,9 +5715,9 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 		zwarn("`continue' active at end of function scope");
Kamil Dudka bde7c9
 	    if (breaks)
Kamil Dudka bde7c9
 		zwarn("`break' active at end of function scope");
Kamil Dudka bde7c9
-	    breaks = obreaks;
Kamil Dudka bde7c9
-	    contflag = ocontflag;
Kamil Dudka bde7c9
-	    loops = oloops;
Kamil Dudka bde7c9
+	    breaks = funcsave->breaks;
Kamil Dudka bde7c9
+	    contflag = funcsave->contflag;
Kamil Dudka bde7c9
+	    loops = funcsave->loops;
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
 	endtrapscope();
Kamil Dudka bde7c9
@@ -5709,11 +5725,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
Kamil Dudka bde7c9
 	if (trap_state == TRAP_STATE_PRIMED)
Kamil Dudka bde7c9
 	    trap_return++;
Kamil Dudka bde7c9
 	ret = lastval;
Kamil Dudka bde7c9
-	noerrexit = savnoerrexit;
Kamil Dudka bde7c9
+	noerrexit = funcsave->noerrexit;
Kamil Dudka bde7c9
 	if (noreturnval) {
Kamil Dudka bde7c9
-	    lastval = oldlastval;
Kamil Dudka bde7c9
-	    numpipestats = oldnumpipestats;
Kamil Dudka bde7c9
-	    memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats);
Kamil Dudka bde7c9
+	    lastval = funcsave->lastval;
Kamil Dudka bde7c9
+	    numpipestats = funcsave->numpipestats;
Kamil Dudka bde7c9
+	    memcpy(pipestats, funcsave->pipestats, sizeof(int)*numpipestats);
Kamil Dudka bde7c9
 	}
Kamil Dudka bde7c9
     } OLDHEAPS;
Kamil Dudka bde7c9
 
Kamil Dudka bde7c9
diff --git a/Src/parse.c b/Src/parse.c
Kamil Dudka bde7c9
index 2705252..d94ee99 100644
Kamil Dudka bde7c9
--- a/Src/parse.c
Kamil Dudka bde7c9
+++ b/Src/parse.c
Kamil Dudka bde7c9
@@ -2737,7 +2737,8 @@ freeeprog(Eprog p)
Kamil Dudka bde7c9
 	DPUTS(p->nref < 0 && !(p->flags & EF_HEAP), "Real EPROG has nref < 0");
Kamil Dudka bde7c9
 	DPUTS(p->nref < -1, "Uninitialised EPROG nref");
Kamil Dudka bde7c9
 #ifdef MAX_FUNCTION_DEPTH
Kamil Dudka bde7c9
-	DPUTS(p->nref > MAX_FUNCTION_DEPTH + 10, "Overlarge EPROG nref");
Kamil Dudka bde7c9
+	DPUTS(zsh_funcnest >=0 && p->nref > zsh_funcnest + 10,
Kamil Dudka bde7c9
+	      "Overlarge EPROG nref");
Kamil Dudka bde7c9
 #endif
Kamil Dudka bde7c9
 	if (p->nref > 0 && !--p->nref) {
Kamil Dudka bde7c9
 	    for (i = p->npats, pp = p->pats; i--; pp++)
Kamil Dudka bde7c9
-- 
Kamil Dudka bde7c9
2.13.6
Kamil Dudka bde7c9