diff options
author | Matt Johnston <matt@ucc.asn.au> | 2011-12-04 05:27:29 +0800 |
---|---|---|
committer | Matt Johnston <matt@ucc.asn.au> | 2011-12-04 05:27:29 +0800 |
commit | baa32218b0df8bd342da9bfe04f7ae678f2664ff (patch) | |
tree | 931403ab67a81374a4a4df9a59999cac999e7184 /common-channel.c | |
parent | fd0b05943df886d71a20219e9ff6baa900b0eb8f (diff) |
- Make sure we don't use channel-specific data after it has been freed
with a ChanType->closehandler()
Diffstat (limited to 'common-channel.c')
-rw-r--r-- | common-channel.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/common-channel.c b/common-channel.c index 5821b08..9eaba50 100644 --- a/common-channel.c +++ b/common-channel.c @@ -138,6 +138,7 @@ struct Channel* newchannel(unsigned int remotechan, 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 @@ static void check_close(struct Channel *channel) { 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 @@ static void check_close(struct Channel *channel) { 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 @@ static void check_in_progress(struct Channel *channel) { /* 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 @@ void recv_msg_channel_request() { 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); |