summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--Src/Zle/zle_main.c35
2 files changed, 34 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index d2f3ecc87..a763ba2d7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -15,6 +15,13 @@
 
 2016-03-20  Barton E. Schaefer  <schaefer@zsh.org>
 
+	* 38191: Src/Zle/zle_main.c: in reexpandprompt(), do not free global
+	pointers until after promptexpand() in case they are referenced from
+	signal handlers, and do additional re-entrancy checks in case of
+	window size changes during promptexpand().
+
+2016-03-20  Barton E. Schaefer  <schaefer@zsh.org>
+
 	* 38188: Src/pattern.c: signal re-entrancy, maybe
 
 2016-03-19  Mikael Magnusson  <mikachu@gmail.com>
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 6e2bfded8..104e5d6c5 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1856,6 +1856,7 @@ void
 reexpandprompt(void)
 {
     static int reexpanding;
+    static int looping;
 
     if (!reexpanding++) {
 	/*
@@ -1866,15 +1867,33 @@ reexpandprompt(void)
 	int local_lastval = lastval;
 	lastval = pre_zle_status;
 
-	free(lpromptbuf);
-	lpromptbuf = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL,
-				  &pmpt_attr);
-	rpmpt_attr = pmpt_attr;
-	free(rpromptbuf);
-	rpromptbuf = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL,
-				  &rpmpt_attr);
+	do {
+	    /* A new SIGWINCH may arrive while in promptexpand(), causing
+	     * looping to increment.  This only happens when a command
+	     * substitution is used in a PROMPT_SUBST prompt, but
+	     * nevertheless keep trying until we see no more changes.
+	     */
+	    char *new_lprompt, *new_rprompt;
+	    looping = reexpanding;
+
+	    new_lprompt = promptexpand(raw_lp ? *raw_lp : NULL, 1, NULL, NULL,
+				       &pmpt_attr);
+	    free(lpromptbuf);
+	    lpromptbuf = new_lprompt;
+
+	    if (looping != reexpanding)
+		continue;
+
+	    rpmpt_attr = pmpt_attr;
+	    new_rprompt = promptexpand(raw_rp ? *raw_rp : NULL, 1, NULL, NULL,
+				       &rpmpt_attr);
+	    free(rpromptbuf);
+	    rpromptbuf = new_rprompt;
+	} while (looping != reexpanding);
+
 	lastval = local_lastval;
-    }
+    } else
+	looping = reexpanding;
     reexpanding--;
 }