From cf7ff70ca73218d618e7c00ab785bcf5f9120a94 Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Mon, 9 May 2016 17:20:14 +0200 Subject: [PATCH] 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. --- src/channel.c | 21 +++++++++++++++++++-- src/structs.h | 3 +++ src/version.c | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/channel.c b/src/channel.c index 8433236227..159a3a0368 100644 --- a/src/channel.c +++ b/src/channel.c @@ -2782,7 +2782,8 @@ channel_wait(channel_T *channel, sock_T fd, int timeout) 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 *channel, char *func) (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 */ diff --git a/src/structs.h b/src/structs.h index 50901acd57..a2b38bffd8 100644 --- 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 diff --git a/src/version.c b/src/version.c index a6f85c3e32..373aff2dd0 100644 --- a/src/version.c +++ b/src/version.c @@ -753,6 +753,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 1826, /**/ 1825, /**/