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

PATCH: bug with redirections on multiple function definitions



My starting point was a seg fault but the easiest demonstration is the
following. It may not come out exactly like this depending on your
memory allocator because we are reading freed memory - the redirection
on b is undefined.
    a a b() {
      body
    } < redirection
    functions b
    b () {
	body
    }body

execfuncdef() is passed the redirection in redir_prog. For the first
function defined, this is copied into the Shfunc structure but a copy is
taken for subsequent functions. However, we have a duplicate name and in
order to add a() a second time, the existing a() is removed which frees
the memory pointed to by redir_prog. This typically gets reused when
making a copy of the function body for b().

The fix below is to use the original value of redir_prog for the last
function added. The nfunc variable was used to determine if we were on
the first function name. I've replaced that with the nonempty test on
the list and assign 0 to redir_prog when using it which perhaps better
reflects the move semantics.

Oliver

diff --git a/Src/exec.c b/Src/exec.c
index e154d1249..216057aa7 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -5042,7 +5042,7 @@ execfuncdef(Estate state, Eprog redir_prog)
     Shfunc shf;
     char *s = NULL;
     int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0, ret = 0;
-    int nfunc = 0, anon_func = 0;
+    int anon_func = 0;
     Wordcode beg = state->pc, end;
     Eprog prog;
     Patprog *pp;
@@ -5118,12 +5118,16 @@ execfuncdef(Estate state, Eprog redir_prog)
 	/*
 	 * redir_prog is permanently allocated --- but if
 	 * this function has multiple names we need an additional
-	 * one.
+	 * one. Original redir_prog used with the last name
+	 * because earlier functions are freed in case of duplicate
+	 * names.
 	 */
-	if (nfunc++ && redir_prog)
+	if (names && nonempty(names) && redir_prog)
 	    shf->redir = dupeprog(redir_prog, 0);
-	else
+	else {
 	    shf->redir = redir_prog;
+	    redir_prog = 0;
+	}
 	shfunc_set_sticky(shf);
 
 	if (!names) {
@@ -5203,7 +5207,7 @@ execfuncdef(Estate state, Eprog redir_prog)
     }
     if (!anon_func)
 	setunderscore("");
-    if (!nfunc && redir_prog) {
+    if (redir_prog) {
 	/* For completeness, shouldn't happen */
 	freeeprog(redir_prog);
     }



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