# HG changeset patch # User Matt Johnston # Date 1322947649 -28800 # Node ID 17962b2a6b8f4f37652cd44da9bbe32f7cbcec85 # Parent a48a1f6ab43e63afe82126316364cb1749c69d68 - Make sure we don't use channel-specific data after it has been freed with a ChanType->closehandler() diff -r a48a1f6ab43e -r 17962b2a6b8f channel.h --- a/channel.h Sun Dec 04 05:24:50 2011 +0800 +++ b/channel.h Sun Dec 04 05:27:29 2011 +0800 @@ -69,6 +69,10 @@ int sent_close, recv_close; int recv_eof, sent_eof; + /* Set after running the ChanType-specific close hander + * to ensure we don't run it twice (nor type->checkclose()). */ + int close_handler_done; + int initconn; /* used for TCP forwarding, whether the channel has been fully initialised */ diff -r a48a1f6ab43e -r 17962b2a6b8f common-channel.c --- a/common-channel.c Sun Dec 04 05:24:50 2011 +0800 +++ b/common-channel.c Sun Dec 04 05:27:29 2011 +0800 @@ -138,6 +138,7 @@ newchan->index = i; newchan->sent_close = newchan->recv_close = 0; newchan->sent_eof = newchan->recv_eof = 0; + newchan->close_handler_done = 0; newchan->remotechan = remotechan; newchan->transwindow = transwindow; @@ -270,7 +271,9 @@ cbuf_getused(channel->writebuf), channel->extrabuf ? cbuf_getused(channel->extrabuf) : 0)) - if (!channel->flushing && channel->type->check_close + if (!channel->flushing + && !channel->close_handler_done + && channel->type->check_close && channel->type->check_close(channel)) { channel->flushing = 1; @@ -281,7 +284,8 @@ channel, to ensure that the shell has exited (and the exit status retrieved) before we close things up. */ if (!channel->type->check_close - || channel->type->check_close(channel)) { + || channel->close_handler_done + || channel->type->check_close(channel)) { close_allowed = 1; } @@ -363,9 +367,11 @@ /* Send the close message and set the channel as closed */ static void send_msg_channel_close(struct Channel *channel) { - TRACE(("enter send_msg_channel_close")) - if (channel->type->closehandler) { + TRACE(("enter send_msg_channel_close %p", channel)) + if (channel->type->closehandler + && !channel->close_handler_done) { channel->type->closehandler(channel); + channel->close_handler_done = 1; } CHECKCLEARTOWRITE(); @@ -568,16 +574,17 @@ struct Channel *channel; - TRACE(("enter recv_msg_channel_request")) - channel = getchannel(); + TRACE(("enter recv_msg_channel_request %p", channel)) + if (channel->sent_close) { TRACE(("leave recv_msg_channel_request: already closed channel")) return; } - if (channel->type->reqhandler) { + if (channel->type->reqhandler + && !channel->close_handler_done) { channel->type->reqhandler(channel); } else { send_msg_channel_failure(channel);