diff options
author | andreas_kupries <akupries@shaw.ca> | 2010-08-04 16:49:02 (GMT) |
---|---|---|
committer | andreas_kupries <akupries@shaw.ca> | 2010-08-04 16:49:02 (GMT) |
commit | d22e96bfc585f1e3d9b592a0dfdeeabe1c6a49e2 (patch) | |
tree | b555a84190f46b5d7da17a5d78f11277a22007b6 /generic/tclIORTrans.c | |
parent | f5169dbe59924b18e67ece3867b7ddddc5820324 (diff) | |
download | tcl-d22e96bfc585f1e3d9b592a0dfdeeabe1c6a49e2.zip tcl-d22e96bfc585f1e3d9b592a0dfdeeabe1c6a49e2.tar.gz tcl-d22e96bfc585f1e3d9b592a0dfdeeabe1c6a49e2.tar.bz2 |
* generic/tclIORChan.c: [Bug 3034840]: Fixed reference counting
* generic/tclIORTrans.c: in InvokeTclMethod and callers.
* tests/ioTrans.test:
Diffstat (limited to 'generic/tclIORTrans.c')
-rw-r--r-- | generic/tclIORTrans.c | 39 |
1 files changed, 30 insertions, 9 deletions
diff --git a/generic/tclIORTrans.c b/generic/tclIORTrans.c index ae1ffc0..54b73c0 100644 --- a/generic/tclIORTrans.c +++ b/generic/tclIORTrans.c @@ -15,7 +15,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIORTrans.c,v 1.17 2010/05/03 11:37:32 nijtmans Exp $ + * RCS: @(#) $Id: tclIORTrans.c,v 1.18 2010/08/04 16:49:02 andreas_kupries Exp $ */ #include "tclInt.h" @@ -587,6 +587,7 @@ TclChanPushObjCmd( */ 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 @@ FreeReflectedTransform( * 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 @@ InvokeTclMethod( /* * 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 @@ InvokeTclMethod( /* * 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 @@ ForwardProc( 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 @@ ForwardProc( 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 @@ ForwardProc( paramPtr->transform.buf = NULL; } } + + Tcl_DecrRefCount(bufObj); break; } @@ -3078,8 +3089,11 @@ TransformRead( /* 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 @@ TransformRead( 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 @@ TransformWrite( /* 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 @@ TransformWrite( bytev = Tcl_GetByteArrayFromObj(resObj, &bytec); res = Tcl_WriteRaw(rtPtr->parent, (char *) bytev, bytec); + + Tcl_DecrRefCount(bufObj); Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */ } |