Subject: Minimal patch to fix iocmd-23.11. Might not be the best fix, but is *a* fix.

From: dgp <[email-masked]>
Date: Thu, 27 Mar 2014 21:35:57 +0000

---
 generic/tclIO.c      | 23 ++++++++++++++++++++---
 generic/tclIORChan.c |  2 ++
 tests/ioCmd.test     |  3 +--
 3 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/generic/tclIO.c b/generic/tclIO.c
index 3636861..c43e61e 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -3852,6 +3852,7 @@ Tcl_GetsObj(
      */
 
     chanPtr = statePtr->topChanPtr;
+    Tcl_Preserve(chanPtr);
 
     bufPtr = statePtr->inQueueHead;
     encoding = statePtr->encoding;
@@ -4144,6 +4145,7 @@ Tcl_GetsObj(
 
   done:
     UpdateInterest(chanPtr);
+    Tcl_Release(chanPtr);
     return copiedTotal;
 }
 
@@ -4189,6 +4191,7 @@ TclGetsObjBinary(
      */
 
     chanPtr = statePtr->topChanPtr;
+    Tcl_Preserve(chanPtr);
 
     bufPtr = statePtr->inQueueHead;
 
@@ -4388,6 +4391,7 @@ TclGetsObjBinary(
 
   done:
     UpdateInterest(chanPtr);
+    Tcl_Release(chanPtr);
     return copiedTotal;
 }
 
@@ -4860,6 +4864,7 @@ Tcl_ReadRaw(
      * requests more bytes.
      */
 
+    Tcl_Preserve(chanPtr);
     for (copied = 0; copied < bytesToRead; copied += copiedNow) {
 	copiedNow = CopyBuffer(chanPtr, bufPtr + copied,
 		bytesToRead - copied);
@@ -4946,7 +4951,7 @@ Tcl_ReadRaw(
 			 * over EAGAIN/WOULDBLOCK handling.
 			 */
 
-			return copied;
+			goto done;
 		    }
 
 		    SetFlag(statePtr, CHANNEL_BLOCKED);
@@ -4954,14 +4959,17 @@ Tcl_ReadRaw(
 		}
 
 		Tcl_SetErrno(result);
-		return -1;
+		copied = -1;
+		goto done;
 	    }
 
-	    return copied + nread;
+	    copied += nread;
+	    goto done;
 	}
     }
 
   done:
+    Tcl_Release(chanPtr);
     return copied;
 }
 
@@ -5069,6 +5077,7 @@ DoReadChars(
     chanPtr = statePtr->topChanPtr;
     encoding = statePtr->encoding;
     factor = UTF_EXPANSION_FACTOR;
+    Tcl_Preserve(chanPtr);
 
     if (appendFlag == 0) {
 	if (encoding == NULL) {
@@ -5158,6 +5167,7 @@ DoReadChars(
 
   done:
     UpdateInterest(chanPtr);
+    Tcl_Release(chanPtr);
     return copied;
 }
 
@@ -7700,6 +7710,11 @@ UpdateInterest(
 				/* State info for channel */
     int mask = statePtr->interestMask;
 
+    if (chanPtr->typePtr == NULL) {
+	/* Do not update interest on a closed channel */
+	return;
+    }
+
     /*
      * If there are flushed buffers waiting to be written, then we need to
      * watch for the channel to become writable.
@@ -8785,6 +8800,7 @@ DoRead(
      * operation.
      */
 
+    Tcl_Preserve(chanPtr);
     if (!(statePtr->flags & CHANNEL_STICKY_EOF)) {
 	ResetFlag(statePtr, CHANNEL_EOF);
     }
@@ -8822,6 +8838,7 @@ DoRead(
 
   done:
     UpdateInterest(chanPtr);
+    Tcl_Release(chanPtr);
     return copied;
 }
 
diff --git a/generic/tclIORChan.c b/generic/tclIORChan.c
index ca3ab4b..affed02 100644
--- a/generic/tclIORChan.c
+++ b/generic/tclIORChan.c
@@ -571,6 +571,7 @@ TclChanCreateObjCmd(
     chan = Tcl_CreateChannel(&tclRChannelType, TclGetString(rcId), rcPtr,
 	    mode);
     rcPtr->chan = chan;
+    Tcl_Preserve(chan);
     chanPtr = (Channel *) chan;
 
     /*
@@ -2145,6 +2146,7 @@ FreeReflectedChannel(
 
 	ckfree((char*) chanPtr->typePtr);
     }
+    Tcl_Release(chanPtr);
 
     n = rcPtr->argc - 2;
     for (i=0; i<n; i++) {
diff --git a/tests/ioCmd.test b/tests/ioCmd.test
index 262be9b..bdf0fb3 100644
--- a/tests/ioCmd.test
+++ b/tests/ioCmd.test
@@ -1024,10 +1024,9 @@ test iocmd-23.11 {chan read, close pulls the rug out} -match glob -body {
     }
     set c [chan create {r} foo]
     note [read $c]
-    close $c
     rename foo {}
     set res
-} -result {{read rc* 4096} {read rc* 4096} snarfsnarf}
+} -result {{read rc* 4096} {}}
 
 # --- === *** ###########################
 # method write
-- 
cgit v0.12