From c3d27ada14acd02db357f2d16347acc22cb17e93 Mon Sep 17 00:00:00 2001
From: Bram Moolenaar <Bram@vim.org>
Date: Mon, 14 Nov 2022 20:52:14 +0000
Subject: [PATCH] patch 9.0.0882: using freed memory after SpellFileMissing
 autocmd uses bwipe

Problem:    Using freed memory after SpellFileMissing autocmd uses bwipe.
Solution:   Bail out if the window no longer exists.
---
 src/buffer.c         |    2 +-
 src/ex_cmds.c        |    2 +-
 src/option.c         |    2 +-
 src/proto/spell.pro  |    2 +-
 src/proto/window.pro |    1 +
 src/spell.c          |   13 ++++++++-----
 src/window.c         |   20 ++++++++++++++++++++
 7 files changed, 33 insertions(+), 9 deletions(-)

--- a/src/spell.c
+++ b/src/spell.c
@@ -4269,9 +4269,10 @@ read_tree_node(fd, byts, idxs, maxidx, s
  * Returns NULL if it's OK, an error message otherwise.
  */
     char_u *
-did_set_spelllang(buf)
-    buf_T	*buf;
+did_set_spelllang(wp)
+    win_T	*wp;
 {
+    buf_T	*buf;
     garray_T	ga;
     char_u	*splp;
     char_u	*region;
@@ -4295,6 +4296,8 @@ did_set_spelllang(buf)
     char_u	*ret_msg = NULL;
     char_u	*spl_copy;
 
+    buf = wp->w_buffer;
+
     /* We don't want to do this recursively.  May happen when a language is
      * not available and the SpellFileMissing autocommand opens a new buffer
      * in which 'spell' is set. */
@@ -4383,7 +4386,7 @@ did_set_spelllang(buf)
 #ifdef FEAT_AUTOCMD
 		/* SpellFileMissing autocommands may do anything, including
 		 * destroying the buffer we are using... */
-		if (!buf_valid(buf))
+		if (!buf_valid(buf) || !win_valid_any_tab(wp))
 		{
 		    ret_msg = (char_u *)"E797: SpellFileMissing autocommand deleted buffer";
 		    goto theend;
@@ -4835,7 +4838,7 @@ spell_reload()
 	    FOR_ALL_WINDOWS(wp)
 		if (wp->w_buffer == buf && wp->w_p_spell)
 		{
-		    (void)did_set_spelllang(buf);
+		    (void)did_set_spelllang(wp);
 # ifdef FEAT_WINDOWS
 		    break;
 # endif
@@ -4872,7 +4875,7 @@ spell_reload_one(fname, added_word)
     /* When "zg" was used and the file wasn't loaded yet, should redo
      * 'spelllang' to load it now. */
     if (added_word && !didit)
-	did_set_spelllang(curbuf);
+	did_set_spelllang(curwin);
 }
 
 
--- a/src/proto/window.pro
+++ b/src/proto/window.pro
@@ -2,6 +2,7 @@
 void do_window __ARGS((int nchar, long Prenum, int xchar));
 int win_split __ARGS((int size, int flags));
 int win_valid __ARGS((win_T *win));
+int win_valid_any_tab __ARGS((win_T *win));
 int win_count __ARGS((void));
 int make_windows __ARGS((int count, int vertical));
 void win_move_after __ARGS((win_T *win1, win_T *win2));
--- a/src/window.c
+++ b/src/window.c
@@ -1242,6 +1242,26 @@ win_valid(win)
 }
 
 /*
+ * Check if "win" is a pointer to an existing window in any tab page.
+ */
+    int
+win_valid_any_tab(win_T *win)
+{
+    win_T	*wp;
+    tabpage_T	*tp;
+
+    if (win == NULL)
+	return FALSE;
+    FOR_ALL_TAB_WINDOWS(tp,wp)
+    {
+	if (wp == win)
+		return TRUE;
+    }
+    return FALSE;
+}
+
+
+/*
  * Return the number of windows.
  */
     int
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1466,7 +1466,7 @@ enter_buffer(buf)
     /* May need to set the spell language.  Can only do this after the buffer
      * has been properly setup. */
     if (!curbuf->b_help && curwin->w_p_spell && *curbuf->b_p_spl != NUL)
-	did_set_spelllang(curbuf);
+	did_set_spelllang(curwin);
 #endif
 
     redraw_later(NOT_VALID);
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -3715,7 +3715,7 @@ do_ecmd(fnum, ffname, sfname, eap, newln
     /* If the window options were changed may need to set the spell language.
      * Can only do this after the buffer has been properly setup. */
     if (did_get_winopts && curwin->w_p_spell && *curbuf->b_p_spl != NUL)
-	did_set_spelllang(curbuf);
+	did_set_spelllang(curwin);
 #endif
 
     if (command == NULL)
--- a/src/option.c
+++ b/src/option.c
@@ -6335,7 +6335,7 @@ did_set_string_option(opt_idx, varp, new
 	    FOR_ALL_WINDOWS(wp)
 		if (wp->w_buffer == curbuf && wp->w_p_spell)
 		{
-		    errmsg = did_set_spelllang(curbuf);
+		    errmsg = did_set_spelllang(wp);
 # ifdef FEAT_WINDOWS
 		    break;
 # endif
--- a/src/proto/spell.pro
+++ b/src/proto/spell.pro
@@ -2,7 +2,7 @@
 int spell_check __ARGS((win_T *wp, char_u *ptr, hlf_T *attrp, int *capcol, int docount));
 int spell_move_to __ARGS((win_T *wp, int dir, int allwords, int curline, hlf_T *attrp));
 void spell_cat_line __ARGS((char_u *buf, char_u *line, int maxlen));
-char_u *did_set_spelllang __ARGS((buf_T *buf));
+char_u *did_set_spelllang __ARGS((win_T *wp));
 void spell_free_all __ARGS((void));
 void spell_reload __ARGS((void));
 int spell_check_msm __ARGS((void));
