patch 8.0.0782: using freed memory in quickfix code

Problem:    Using freed memory in quickfix code. (Dominique Pelle)
Solution:   Handle a help window differently. (Yegappan Lakshmanan)
diff --git a/src/buffer.c b/src/buffer.c
index 4dbb9e9..4510078 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -249,7 +249,7 @@
 	netbeansFireChanges = oldFire;
 #endif
 	/* Help buffer is filtered. */
-	if (curbuf->b_help)
+	if (bt_help(curbuf))
 	    fix_help_buffer();
     }
     else if (read_stdin)
@@ -5669,6 +5669,15 @@
 }
 
 /*
+ * Return TRUE if "buf" is a help buffer.
+ */
+    int
+bt_help(buf_T *buf)
+{
+    return buf != NULL && buf->b_help;
+}
+
+/*
  * Return TRUE if "buf" is a "nofile", "acwrite" or "terminal" buffer.
  * This means the buffer name is not a file name.
  */
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 9c84e24..6ec3ded 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -6314,7 +6314,7 @@
      * Re-use an existing help window or open a new one.
      * Always open a new one for ":tab help".
      */
-    if (!curwin->w_buffer->b_help
+    if (!bt_help(curwin->w_buffer)
 #ifdef FEAT_WINDOWS
 	    || cmdmod.tab != 0
 #endif
@@ -6325,7 +6325,7 @@
 	    wp = NULL;
 	else
 	    FOR_ALL_WINDOWS(wp)
-		if (wp->w_buffer != NULL && wp->w_buffer->b_help)
+		if (bt_help(wp->w_buffer))
 		    break;
 	if (wp != NULL && wp->w_buffer->b_nwindows > 0)
 	    win_enter(wp, TRUE);
@@ -6425,7 +6425,7 @@
 
     FOR_ALL_WINDOWS(win)
     {
-	if (win->w_buffer->b_help)
+	if (bt_help(win->w_buffer))
 	{
 	    win_close(win, FALSE);
 	    return;
diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro
index e9a37de..a671075 100644
--- a/src/proto/buffer.pro
+++ b/src/proto/buffer.pro
@@ -55,6 +55,7 @@
 void write_viminfo_bufferlist(FILE *fp);
 int bt_quickfix(buf_T *buf);
 int bt_terminal(buf_T *buf);
+int bt_help(buf_T *buf);
 int bt_nofile(buf_T *buf);
 int bt_dontwrite(buf_T *buf);
 int bt_dontwrite_msg(buf_T *buf);
diff --git a/src/quickfix.c b/src/quickfix.c
index c34e34d..79cb416 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -2101,7 +2101,7 @@
     /*
      * For ":helpgrep" find a help window or open one.
      */
-    if (qf_ptr->qf_type == 1 && (!curwin->w_buffer->b_help || cmdmod.tab != 0))
+    if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0))
     {
 	win_T	*wp;
 
@@ -2109,7 +2109,7 @@
 	    wp = NULL;
 	else
 	    FOR_ALL_WINDOWS(wp)
-		if (wp->w_buffer != NULL && wp->w_buffer->b_help)
+		if (bt_help(wp->w_buffer))
 		    break;
 	if (wp != NULL && wp->w_buffer->b_nwindows > 0)
 	    win_enter(wp, TRUE);
@@ -5343,10 +5343,14 @@
 
     if (eap->cmdidx == CMD_lhelpgrep)
     {
-	/* Find an existing help window */
-	FOR_ALL_WINDOWS(wp)
-	    if (wp->w_buffer != NULL && wp->w_buffer->b_help)
-		break;
+	/* If the current window is a help window, then use it */
+	if (bt_help(curwin->w_buffer))
+	    wp = curwin;
+	else
+	    /* Find an existing help window */
+	    FOR_ALL_WINDOWS(wp)
+		if (bt_help(wp->w_buffer))
+		    break;
 
 	if (wp == NULL)	    /* Help window not found */
 	    qi = NULL;
@@ -5515,7 +5519,7 @@
     {
 	/* If the help window is not opened or if it already points to the
 	 * correct location list, then free the new location list. */
-	if (!curwin->w_buffer->b_help || curwin->w_llist == qi)
+	if (!bt_help(curwin->w_buffer) || curwin->w_llist == qi)
 	{
 	    if (new_qi)
 		ll_free_all(&qi);
diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim
index 7b344ea..41e5021 100644
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -2287,3 +2287,17 @@
     call Xchangedtick_tests('c')
     call Xchangedtick_tests('l')
 endfunc
+
+" Open multiple help windows using ":lhelpgrep
+" This test used to crash Vim
+func Test_Multi_LL_Help()
+    new | only
+    lhelpgrep window
+    lopen
+    e#
+    lhelpgrep buffer
+    call assert_equal(3, winnr('$'))
+    call assert_true(len(getloclist(1)) != 0)
+    call assert_true(len(getloclist(2)) != 0)
+    new | only
+endfunc
diff --git a/src/version.c b/src/version.c
index f62d3f0..da00188 100644
--- a/src/version.c
+++ b/src/version.c
@@ -770,6 +770,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    782,
+/**/
     781,
 /**/
     780,
diff --git a/src/window.c b/src/window.c
index 1927217..948303c 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2314,7 +2314,7 @@
 
     /* When closing the help window, try restoring a snapshot after closing
      * the window.  Otherwise clear the snapshot, it's now invalid. */
-    if (win->w_buffer != NULL && win->w_buffer->b_help)
+    if (bt_help(win->w_buffer))
 	help_window = TRUE;
     else
 	clear_snapshot(curtab, SNAP_HELP_IDX);
@@ -2397,7 +2397,7 @@
 	    && (last_window() || curtab != prev_curtab
 		|| close_last_window_tabpage(win, free_buf, prev_curtab)))
     {
-	/* Autocommands have close all windows, quit now.  Restore
+	/* Autocommands have closed all windows, quit now.  Restore
 	 * curwin->w_buffer, otherwise writing viminfo may fail. */
 	if (curwin->w_buffer == NULL)
 	    curwin->w_buffer = curbuf;
@@ -6479,7 +6479,7 @@
 
     FOR_ALL_WINDOWS(wp)
 	if (wp->w_buffer != NULL
-		&& (!((wp->w_buffer->b_help && !curbuf->b_help)
+		&& (!((bt_help(wp->w_buffer) && !bt_help(curbuf))
 # ifdef FEAT_QUICKFIX
 		    || wp->w_p_pvw
 # endif