changeset 9083:69bb7b230094 v7.4.1826

commit https://github.com/vim/vim/commit/cf7ff70ca73218d618e7c00ab785bcf5f9120a94 Author: Bram Moolenaar <Bram@vim.org> Date: Mon May 9 17:20:14 2016 +0200 patch 7.4.1826 Problem: Callbacks are invoked when it's not safe. (Andrew Stewart) Solution: When a channel is to be closed don't invoke callbacks right away, wait for a safe moment.
author Christian Brabandt <cb@256bit.org>
date Mon, 09 May 2016 17:30:06 +0200
parents ed95e35d74bd
children 8d3354777bf1
files src/channel.c src/structs.h src/version.c
diffstat 3 files changed, 24 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/src/channel.c
+++ b/src/channel.c
@@ -2782,7 +2782,8 @@ channel_wait(channel_T *channel, sock_T 
 channel_close_on_error(channel_T *channel, char *func)
 {
     /* Do not call emsg(), most likely the other end just exited. */
-    ch_errors(channel, "%s(): Cannot read from channel", func);
+    ch_errors(channel, "%s(): Cannot read from channel, will close it soon",
+									func);
 
     /* Queue a "DETACH" netbeans message in the command queue in order to
      * terminate the netbeans session later. Do not end the session here
@@ -2800,7 +2801,15 @@ channel_close_on_error(channel_T *channe
 			      (int)STRLEN(DETACH_MSG_RAW), FALSE, "PUT ");
 
     /* When reading from stdout is not possible, assume the other side has
-     * died. */
+     * died.  Don't close the channel right away, it may be the wrong moment
+     * to invoke callbacks. */
+    channel->ch_to_be_closed = TRUE;
+}
+
+    static void
+channel_close_now(channel_T *channel)
+{
+    ch_log(channel, "Closing channel because of previous read error");
     channel_close(channel, TRUE);
     if (channel->ch_nb_close_cb != NULL)
 	(*channel->ch_nb_close_cb)();
@@ -3515,6 +3524,14 @@ channel_parse_messages(void)
     }
     while (channel != NULL)
     {
+	if (channel->ch_to_be_closed)
+	{
+	    channel->ch_to_be_closed = FALSE;
+	    channel_close_now(channel);
+	    /* channel may have been freed, start over */
+	    channel = first_channel;
+	    continue;
+	}
 	if (channel->ch_refcount == 0 && !channel_still_useful(channel))
 	{
 	    /* channel is no longer useful, free it */
--- a/src/structs.h
+++ b/src/structs.h
@@ -1416,6 +1416,9 @@ struct channel_S {
     char	*ch_hostname;	/* only for socket, allocated */
     int		ch_port;	/* only for socket */
 
+    int		ch_to_be_closed; /* When TRUE reading or writing failed and
+				  * the channel must be closed when it's safe
+				  * to invoke callbacks. */
     int		ch_error;	/* When TRUE an error was reported.  Avoids
 				 * giving pages full of error messages when
 				 * the other side has exited, only mention the
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1826,
+/**/
     1825,
 /**/
     1824,