Tcl Source Code

Artifact [aabfbe09fc]
Login

Artifact aabfbe09fcff56590bbbc3bb674ca4008b99d6ac:

Attachment "tclIORTrans.patch" to ticket [3034840fff] added by andreas_kupries 2010-08-04 04:54:47.
Index: generic/tclIORTrans.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclIORTrans.c,v
retrieving revision 1.17
diff -w -u -r1.17 tclIORTrans.c
--- generic/tclIORTrans.c	3 May 2010 11:37:32 -0000	1.17
+++ generic/tclIORTrans.c	3 Aug 2010 21:45:37 -0000
@@ -587,6 +587,7 @@
      */
 
     modeObj = DecodeEventMask(mode);
+    /* assert modeObj.refCount == 1 */
     result = InvokeTclMethod(rtPtr, "initialize", modeObj, NULL, &resObj);
     Tcl_DecrRefCount(modeObj);
     if (result != TCL_OK) {
@@ -1913,6 +1914,11 @@
  * Side effects:
  *	Arbitrary, as it calls upon a Tcl script.
  *
+ * Contract:
+ *	argOneObj.refCount >= 1 on entry and exit, if argOneObj != NULL
+ *	argTwoObj.refCount >= 1 on entry and exit, if argTwoObj != NULL
+ *	resObj.refCount in {0, 1, ...}
+ *
  *----------------------------------------------------------------------
  * Semi-DUPLICATE of 'InvokeTclMethod' in tclIORChan.c
  * - Semi because different structures are used.
@@ -1966,15 +1972,16 @@
     /*
      * Append the additional argument containing method specific details
      * behind the channel id. If specified.
+     *
+     * Because of the contract there is no need to increment the refcounts.
+     * The objects will survive the Tcl_EvalObjv without change.
      */
 
     cmdc = rtPtr->argc;
     if (argOneObj) {
-	Tcl_IncrRefCount(argOneObj);
 	rtPtr->argv[cmdc] = argOneObj;
 	cmdc++;
 	if (argTwoObj) {
-	    Tcl_IncrRefCount(argTwoObj);
 	    rtPtr->argv[cmdc] = argTwoObj;
 	    cmdc++;
 	}
@@ -2035,15 +2042,13 @@
 
     /*
      * Cleanup of the dynamic parts of the command.
+     *
+     * The detail objects survived the Tcl_EvalObjv without change because of
+     * the contract. Therefore there is no need to decrement the refcounts. Only
+     * the internal method object has to be disposed of.
      */
 
     Tcl_DecrRefCount(methObj);
-    if (argOneObj) {
-	Tcl_DecrRefCount(argOneObj);
-	if (argTwoObj) {
-	    Tcl_DecrRefCount(argTwoObj);
-	}
-    }
 
     /*
      * The resObj has a ref count of 1 at this location. This means that the
@@ -2553,6 +2558,7 @@
     case ForwardedInput: {
 	Tcl_Obj *bufObj = Tcl_NewByteArrayObj((unsigned char *)
 		paramPtr->transform.buf, paramPtr->transform.size);
+	Tcl_IncrRefCount(bufObj);
 
 	if (InvokeTclMethod(rtPtr, "read", bufObj, NULL, &resObj) != TCL_OK) {
 	    ForwardSetObjError(paramPtr, resObj);
@@ -2578,12 +2584,15 @@
 		paramPtr->transform.buf = NULL;
 	    }
 	}
+
+	Tcl_DecrRefCount(bufObj);
 	break;
     }
 
     case ForwardedOutput: {
 	Tcl_Obj *bufObj = Tcl_NewByteArrayObj((unsigned char *)
 		paramPtr->transform.buf, paramPtr->transform.size);
+	Tcl_IncrRefCount(bufObj);
 
 	if (InvokeTclMethod(rtPtr, "write", bufObj, NULL, &resObj) != TCL_OK) {
 	    ForwardSetObjError(paramPtr, resObj);
@@ -2609,6 +2618,8 @@
 		paramPtr->transform.buf = NULL;
 	    }
 	}
+
+	Tcl_DecrRefCount(bufObj);
 	break;
     }
 
@@ -3078,8 +3089,11 @@
     /* ASSERT: rtPtr->mode & TCL_READABLE */
 
     bufObj = Tcl_NewByteArrayObj((unsigned char *) buf, toRead);
+    Tcl_IncrRefCount(bufObj);
+
     if (InvokeTclMethod(rtPtr, "read", bufObj, NULL, &resObj) != TCL_OK) {
 	Tcl_SetChannelError(rtPtr->chan, resObj);
+	Tcl_DecrRefCount(bufObj);
 	Tcl_DecrRefCount(resObj);	/* Remove reference held from invoke */
 	*errorCodePtr = EINVAL;
 	return 0;
@@ -3087,6 +3101,8 @@
 
     bytev = Tcl_GetByteArrayFromObj(resObj, &bytec);
     ResultAdd(&rtPtr->result, bytev, bytec);
+
+    Tcl_DecrRefCount(bufObj);
     Tcl_DecrRefCount(resObj);		/* Remove reference held from invoke */
     return 1;
 }
@@ -3134,9 +3150,12 @@
 	/* ASSERT: rtPtr->mode & TCL_WRITABLE */
 
 	bufObj = Tcl_NewByteArrayObj((unsigned char *) buf, toWrite);
+	Tcl_IncrRefCount(bufObj);
 	if (InvokeTclMethod(rtPtr, "write", bufObj, NULL, &resObj) != TCL_OK) {
 	    *errorCodePtr = EINVAL;
 	    Tcl_SetChannelError(rtPtr->chan, resObj);
+
+	    Tcl_DecrRefCount(bufObj);
 	    Tcl_DecrRefCount(resObj);	/* Remove reference held from invoke */
 	    return 0;
 	}
@@ -3145,6 +3164,8 @@
 
 	bytev = Tcl_GetByteArrayFromObj(resObj, &bytec);
 	res = Tcl_WriteRaw(rtPtr->parent, (char *) bytev, bytec);
+
+	Tcl_DecrRefCount(bufObj);
 	Tcl_DecrRefCount(resObj);	/* Remove reference held from invoke */
     }
 
Index: tests/ioTrans.test
===================================================================
RCS file: /cvsroot/tcl/tcl/tests/ioTrans.test,v
retrieving revision 1.8
diff -w -u -r1.8 ioTrans.test
--- tests/ioTrans.test	17 Mar 2010 16:35:42 -0000	1.8
+++ tests/ioTrans.test	3 Aug 2010 21:45:37 -0000
@@ -854,6 +854,28 @@
 } -constraints {testchannel impossible} \
     -result {Owner lost}
 
+
+test iortrans-11.2 {delete interp of reflected transform} -body {
+    interp create slave
+
+    # Magic to get the test* commands into the slave
+    load {} Tcltest slave
+
+    # Get base channel into the slave
+    set c [tempchan]
+    testchannel cut $c
+    interp eval slave [list testchannel splice $c]
+    interp eval slave [list set c $c]
+
+    slave eval {
+        proc no-op args {}
+        proc driver {c sub args} {return {initialize finalize read write}}
+	set t [chan push $c [list driver $c]]
+        chan event $c readable no-op
+    }
+    interp delete slave
+} -result {} -constraints {testchannel}
+
 # ### ### ### ######### ######### #########
 ## Same tests as above, but exercising the code forwarding and
 ## receiving driver operations to the originator thread.