patch 8.2.3426: crash when deleting a listener in a listener callback

Problem:    Crash when deleting a listener in a listener callback. (Naohiro
            Ono)
Solution:   Mark the listener and delete it later.
diff --git a/src/change.c b/src/change.c
index 799aa5e..e171956 100644
--- a/src/change.c
+++ b/src/change.c
@@ -293,6 +293,18 @@
     invoke_listeners(buf);
 }
 
+
+    static void
+remove_listener(buf_T *buf, listener_T *lnr, listener_T *prev)
+{
+    if (prev != NULL)
+	prev->lr_next = lnr->lr_next;
+    else
+	buf->b_listener = lnr->lr_next;
+    free_callback(&lnr->lr_callback);
+    vim_free(lnr);
+}
+
 /*
  * listener_remove() function
  */
@@ -317,12 +329,13 @@
 	    next = lnr->lr_next;
 	    if (lnr->lr_id == id)
 	    {
-		if (prev != NULL)
-		    prev->lr_next = lnr->lr_next;
-		else
-		    buf->b_listener = lnr->lr_next;
-		free_callback(&lnr->lr_callback);
-		vim_free(lnr);
+		if (textwinlock > 0)
+		{
+		    // in invoke_listeners(), clear ID and delete later
+		    lnr->lr_id = 0;
+		    return;
+		}
+		remove_listener(buf, lnr, prev);
 		rettv->vval.v_number = 1;
 		return;
 	    }
@@ -357,6 +370,7 @@
     linenr_T	added = 0;
     int		save_updating_screen = updating_screen;
     static int	recursive = FALSE;
+    listener_T	*next;
 
     if (buf->b_recorded_changes == NULL  // nothing changed
 	    || buf->b_listener == NULL   // no listeners
@@ -400,6 +414,18 @@
 	clear_tv(&rettv);
     }
 
+    // If f_listener_remove() was called may have to remove a listener now.
+    for (lnr = buf->b_listener; lnr != NULL; lnr = next)
+    {
+	listener_T	*prev = NULL;
+
+	next = lnr->lr_next;
+	if (lnr->lr_id == 0)
+	    remove_listener(buf, lnr, prev);
+	else
+	    prev = lnr;
+    }
+
     --textwinlock;
     list_unref(buf->b_recorded_changes);
     buf->b_recorded_changes = NULL;