changeset 652:17962b2a6b8f

- Make sure we don't use channel-specific data after it has been freed with a ChanType->closehandler()
author Matt Johnston <matt@ucc.asn.au>
date Sun, 04 Dec 2011 05:27:29 +0800
parents a48a1f6ab43e
children 5e8d84f3ee72
files channel.h common-channel.c
diffstat 2 files changed, 18 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- 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 */
 
--- 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);