about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--Src/hashtable.c1
-rw-r--r--Src/hist.c42
-rw-r--r--Src/zsh.h1
4 files changed, 35 insertions, 15 deletions
diff --git a/ChangeLog b/ChangeLog
index e608b167f..b5060864a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2017-05-18  Peter Stephenson  <p.stephenson@samsung.com>
+
+	* 41113 (tweaked): Src/hashtable,c, Src/hist.c, Src/zsh.h: Save
+	and restore state of linking of current history line into history
+	ring, to avoid an attempt to free the current history line.
+
 2017-05-12  Jun-ichi Takimoto <takimoto-j@kba.biglobe.ne.jp>
 
 	* 41090: Src/Zle/zle_refresh.c, Src/compat.c, Src/pattern.c,
diff --git a/Src/hashtable.c b/Src/hashtable.c
index ba5faad91..c34744cd8 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -1448,6 +1448,7 @@ freehistdata(Histent he, int unlink)
     if (!(he->node.flags & (HIST_DUP | HIST_TMPSTORE)))
 	removehashnode(histtab, he->node.nam);
 
+    DPUTS(he->node.nam == chline, "Attempt to free chline in history data");
     zsfree(he->node.nam);
     if (he->nwords)
 	zfree(he->words, he->nwords*2*sizeof(short));
diff --git a/Src/hist.c b/Src/hist.c
index 350688d2d..4c1039b67 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -87,6 +87,9 @@ mod_export zlong curhist;
 /**/
 struct histent curline;
 
+/***/
+int curline_linked;
+
 /* current line count of allocated history entries */
 
 /**/
@@ -261,6 +264,9 @@ hist_context_save(struct hist_stack *hs, int toplevel)
      */
     hs->cstack = cmdstack;
     hs->csp = cmdsp;
+    hs->curline_linked = curline_linked;
+
+    unlinkcurline();
 
     stophist = 0;
     chline = NULL;
@@ -300,6 +306,9 @@ hist_context_restore(const struct hist_stack *hs, int toplevel)
 	zfree(cmdstack, CMDSTACKSZ);
     cmdstack = hs->cstack;
     cmdsp = hs->csp;
+    unlinkcurline();
+    if (hs->curline_linked)
+	linkcurline();
 }
 
 /*
@@ -990,6 +999,7 @@ nohwe(void)
 
 /* these functions handle adding/removing curline to/from the hist_ring */
 
+/**/
 static void
 linkcurline(void)
 {
@@ -1002,11 +1012,15 @@ linkcurline(void)
 	hist_ring = &curline;
     }
     curline.histnum = ++curhist;
+    curline_linked = 1;
 }
 
+/**/
 static void
 unlinkcurline(void)
 {
+    if (!curline_linked)
+	return;
     curline.up->down = curline.down;
     curline.down->up = curline.up;
     if (hist_ring == &curline) {
@@ -1016,6 +1030,7 @@ unlinkcurline(void)
 	    hist_ring = curline.up;
     }
     curhist--;
+    curline_linked = 0;
 }
 
 /* initialize the history mechanism */
@@ -1035,6 +1050,7 @@ hbegin(int dohist)
 	stophist = (!interact || unset(SHINSTDIN)) ? 2 : 0;
     else
 	stophist = 0;
+    DPUTS(chline != NULL, "chline set at start of history");
     /*
      * pws: We used to test for "|| (inbufflags & INP_ALIAS)"
      * in this test, but at this point we don't have input
@@ -1292,11 +1308,10 @@ putoldhistentryontop(short keep_going)
 Histent
 prepnexthistent(void)
 {
-    Histent he; 
-    int curline_in_ring = hist_ring == &curline;
+    Histent he;
+    int relink_curline = curline_linked;
 
-    if (curline_in_ring)
-	unlinkcurline();
+    unlinkcurline();
     if (hist_ring && hist_ring->node.flags & HIST_TMPSTORE) {
 	curhist--;
 	freehistnode(&hist_ring->node);
@@ -1320,7 +1335,7 @@ prepnexthistent(void)
 	he = hist_ring;
     }
     he->histnum = ++curhist;
-    if (curline_in_ring)
+    if (relink_curline)
 	linkcurline();
     return he;
 }
@@ -1395,8 +1410,7 @@ hend(Eprog prog)
     queue_signals();
     if (histdone & HISTFLAG_SETTY)
 	settyinfo(&shttyinfo);
-    if (!(histactive & HA_NOINC))
-	unlinkcurline();
+    unlinkcurline();
     if (histactive & HA_NOINC) {
 	zfree(chline, hlinesz);
 	zfree(chwords, chwordlen*sizeof(short));
@@ -3624,7 +3638,7 @@ int
 pushhiststack(char *hf, zlong hs, zlong shs, int level)
 {
     struct histsave *h;
-    int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline;
+    int relink_curline = curline_linked;
 
     if (histsave_stack_pos == histsave_stack_size) {
 	histsave_stack_size += 5;
@@ -3632,8 +3646,7 @@ pushhiststack(char *hf, zlong hs, zlong shs, int level)
 			    histsave_stack_size * sizeof (struct histsave));
     }
 
-    if (curline_in_ring)
-	unlinkcurline();
+    unlinkcurline();
 
     h = &histsave_stack[histsave_stack_pos++];
 
@@ -3668,7 +3681,7 @@ pushhiststack(char *hf, zlong hs, zlong shs, int level)
     savehistsiz = shs;
     inithist(); /* sets histtab */
 
-    if (curline_in_ring)
+    if (relink_curline)
 	linkcurline();
 
     return histsave_stack_pos;
@@ -3680,13 +3693,12 @@ int
 pophiststack(void)
 {
     struct histsave *h;
-    int curline_in_ring = (histactive & HA_ACTIVE) && hist_ring == &curline;
+    int relink_curline = curline_linked;
 
     if (histsave_stack_pos == 0)
 	return 0;
 
-    if (curline_in_ring)
-	unlinkcurline();
+    unlinkcurline();
 
     deletehashtable(histtab);
     zsfree(lasthist.text);
@@ -3709,7 +3721,7 @@ pophiststack(void)
     histsiz = h->histsiz;
     savehistsiz = h->savehistsiz;
 
-    if (curline_in_ring)
+    if (relink_curline)
 	linkcurline();
 
     return histsave_stack_pos + 1;
diff --git a/Src/zsh.h b/Src/zsh.h
index 22f73f806..405b27490 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2931,6 +2931,7 @@ struct hist_stack {
     void (*addtoline) _((int));
     unsigned char *cstack;
     int csp;
+    int curline_linked;
 };
 
 /*