Attachment "patch-85" to
ticket [2978773fff]
added by
andreas_kupries
2010-03-31 02:59:30.
--- tcl85.orig/ChangeLog 2010-03-30 11:08:59.000000000 -0800
+++ tcl85/ChangeLog 2010-03-30 11:42:00.000000000 -0800
@@ -1,3 +1,12 @@
+2010-03-30 Andreas Kupries <[email protected]>
+
+ * generic/tclIORChan.c (ReflectClose, ReflectInput, ReflectOutput,
+ ReflectSeekWide, ReflectWatch, ReflectBlock, ReflectSetOption,
+ ReflectGetOption, ForwardProc): [Bug 2978773]: Preserve
+ ReflectedChannel* structures across handler invokations, to avoid
+ crashes when the handler implementation induces nested callbacks
+ and destruction of the channel deep inside such a nesting.
+
2010-03-30 Don Porter <[email protected]>
* generic/tclObj.c (Tcl_GetCommandFromObj): [Bug 2979402]: Reorder
--- tcl85.orig/generic/tclIORChan.c 2010-03-30 11:08:59.000000000 -0800
+++ tcl85/generic/tclIORChan.c 2010-03-30 11:52:55.000000000 -0800
@@ -1082,7 +1082,7 @@
}
#endif
- FreeReflectedChannel(rcPtr);
+ Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
return EOK;
}
@@ -1094,7 +1094,7 @@
*/
if (rcPtr->methods == 0) {
- FreeReflectedChannel(rcPtr);
+ Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
return EOK;
}
@@ -1157,7 +1157,7 @@
}
#endif
- FreeReflectedChannel(rcPtr);
+ Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
#ifdef TCL_THREADS
}
#endif
@@ -1238,29 +1238,26 @@
/* ASSERT: rcPtr->method & FLAG(METH_READ) */
/* ASSERT: rcPtr->mode & TCL_READABLE */
+ Tcl_Preserve(rcPtr);
+
toReadObj = Tcl_NewIntObj(toRead);
if (InvokeTclMethod(rcPtr, "read", toReadObj, NULL, &resObj)!=TCL_OK) {
int code = ErrnoReturn (rcPtr, resObj);
if (code < 0) {
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
*errorCodePtr = -code;
- return -1;
+ goto error;
}
Tcl_SetChannelError(rcPtr->chan, resObj);
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
- *errorCodePtr = EINVAL;
- return -1;
+ goto invalid;
}
bytev = Tcl_GetByteArrayFromObj(resObj, &bytec);
if (toRead < bytec) {
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
SetChannelErrorStr(rcPtr->chan, msg_read_toomuch);
- *errorCodePtr = EINVAL;
- return -1;
+ goto invalid;
}
*errorCodePtr = EOK;
@@ -1269,8 +1266,15 @@
memcpy(buf, bytev, (size_t)bytec);
}
+ stop:
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
+ Tcl_Release(rcPtr);
return bytec;
+ invalid:
+ *errorCodePtr = EINVAL;
+ error:
+ bytec = -1;
+ goto stop;
}
/*
@@ -1346,31 +1350,27 @@
/* ASSERT: rcPtr->method & FLAG(METH_WRITE) */
/* ASSERT: rcPtr->mode & TCL_WRITABLE */
+ Tcl_Preserve(rcPtr);
+
bufObj = Tcl_NewByteArrayObj((unsigned char *) buf, toWrite);
if (InvokeTclMethod(rcPtr, "write", bufObj, NULL, &resObj) != TCL_OK) {
int code = ErrnoReturn(rcPtr, resObj);
if (code < 0) {
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
*errorCodePtr = -code;
- return -1;
+ goto error;
}
Tcl_SetChannelError(rcPtr->chan, resObj);
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
- *errorCodePtr = EINVAL;
- return -1;
+ goto invalid;
}
if (Tcl_GetIntFromObj(rcPtr->interp, resObj, &written) != TCL_OK) {
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
Tcl_SetChannelError(rcPtr->chan, MarshallError(rcPtr->interp));
- *errorCodePtr = EINVAL;
- return -1;
+ goto invalid;
}
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
-
if ((written == 0) && (toWrite > 0)) {
/*
* The handler claims to have written nothing of what it was
@@ -1378,8 +1378,7 @@
*/
SetChannelErrorStr(rcPtr->chan, msg_write_nothing);
- *errorCodePtr = EINVAL;
- return -1;
+ goto invalid;
}
if (toWrite < written) {
/*
@@ -1389,12 +1388,19 @@
*/
SetChannelErrorStr(rcPtr->chan, msg_write_toomuch);
- *errorCodePtr = EINVAL;
- return -1;
+ goto invalid;
}
*errorCodePtr = EOK;
+ stop:
+ Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
+ Tcl_Release(rcPtr);
return written;
+ invalid:
+ *errorCodePtr = EINVAL;
+ error:
+ written = -1;
+ goto stop;
}
/*
@@ -1452,33 +1458,35 @@
/* ASSERT: rcPtr->method & FLAG(METH_SEEK) */
+ Tcl_Preserve(rcPtr);
+
offObj = Tcl_NewWideIntObj(offset);
baseObj = Tcl_NewStringObj((seekMode == SEEK_SET) ? "start" :
((seekMode == SEEK_CUR) ? "current" : "end"), -1);
if (InvokeTclMethod(rcPtr, "seek", offObj, baseObj, &resObj)!=TCL_OK) {
Tcl_SetChannelError(rcPtr->chan, resObj);
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
- *errorCodePtr = EINVAL;
- return -1;
+ goto invalid;
}
if (Tcl_GetWideIntFromObj(rcPtr->interp, resObj, &newLoc) != TCL_OK) {
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
Tcl_SetChannelError(rcPtr->chan, MarshallError(rcPtr->interp));
- *errorCodePtr = EINVAL;
- return -1;
+ goto invalid;
}
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
-
if (newLoc < Tcl_LongAsWide(0)) {
SetChannelErrorStr(rcPtr->chan, msg_seek_beforestart);
- *errorCodePtr = EINVAL;
- return -1;
+ goto invalid;
}
*errorCodePtr = EOK;
+ stop:
+ Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
+ Tcl_Release(rcPtr);
return newLoc;
+ invalid:
+ *errorCodePtr = EINVAL;
+ newLoc = -1;
+ goto stop;
}
static int
@@ -1564,9 +1572,13 @@
}
#endif
+ Tcl_Preserve(rcPtr);
+
maskObj = DecodeEventMask(mask);
(void) InvokeTclMethod(rcPtr, "watch", maskObj, NULL, NULL);
Tcl_DecrRefCount(maskObj);
+
+ Tcl_Release(rcPtr);
}
/*
@@ -1619,6 +1631,8 @@
blockObj = Tcl_NewBooleanObj(!nonblocking);
+ Tcl_Preserve(rcPtr);
+
if (InvokeTclMethod(rcPtr, "blocking", blockObj, NULL, &resObj) != TCL_OK) {
Tcl_SetChannelError(rcPtr->chan, resObj);
errorNum = EINVAL;
@@ -1627,6 +1641,8 @@
}
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
+
+ Tcl_Release(rcPtr);
return errorNum;
}
@@ -1682,6 +1698,7 @@
return p.base.code;
}
#endif
+ Tcl_Preserve(rcPtr);
optionObj = Tcl_NewStringObj(optionName, -1);
valueObj = Tcl_NewStringObj(newValue, -1);
@@ -1691,6 +1708,7 @@
}
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
+ Tcl_Release(rcPtr);
return result;
}
@@ -1777,10 +1795,11 @@
optionObj = Tcl_NewStringObj(optionName, -1);
}
+ Tcl_Preserve(rcPtr);
+
if (InvokeTclMethod(rcPtr, method, optionObj, NULL, &resObj)!=TCL_OK) {
UnmarshallErrorResult(interp, resObj);
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
- return TCL_ERROR;
+ goto error;
}
/*
@@ -1790,8 +1809,7 @@
if (optionObj != NULL) {
Tcl_DStringAppend(dsPtr, TclGetString(resObj), -1);
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
- return TCL_OK;
+ goto ok;
}
/*
@@ -1806,8 +1824,7 @@
*/
if (Tcl_ListObjGetElements(interp, resObj, &listc, &listv) != TCL_OK) {
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
- return TCL_ERROR;
+ goto error;
}
if ((listc % 2) == 1) {
@@ -1820,8 +1837,7 @@
"Expected list with even number of "
"elements, got %d element%s instead", listc,
(listc == 1 ? "" : "s")));
- Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
- return TCL_ERROR;
+ goto error;
} else {
int len;
char *str = Tcl_GetStringFromObj(resObj, &len);
@@ -1830,9 +1846,17 @@
Tcl_DStringAppend(dsPtr, " ", 1);
Tcl_DStringAppend(dsPtr, str, len);
}
+ goto ok;
+ }
+
+ ok:
Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
+ Tcl_Release(rcPtr);
return TCL_OK;
- }
+ error:
+ Tcl_DecrRefCount(resObj); /* Remove reference held from invoke */
+ Tcl_Release(rcPtr);
+ return TCL_ERROR;
}
/*
@@ -2816,12 +2840,13 @@
Tcl_GetChannelName (rcPtr->chan));
Tcl_DeleteHashEntry (hPtr);
- FreeReflectedChannel(rcPtr);
+ Tcl_EventuallyFree (rcPtr, (Tcl_FreeProc *) FreeReflectedChannel);
break;
case ForwardedInput: {
Tcl_Obj *toReadObj = Tcl_NewIntObj(paramPtr->input.toRead);
+ Tcl_Preserve(rcPtr);
if (InvokeTclMethod(rcPtr, "read", toReadObj, NULL, &resObj)!=TCL_OK){
int code = ErrnoReturn (rcPtr, resObj);
@@ -2851,6 +2876,7 @@
paramPtr->input.toRead = bytec;
}
}
+ Tcl_Release(rcPtr);
break;
}
@@ -2858,6 +2884,7 @@
Tcl_Obj *bufObj = Tcl_NewByteArrayObj((unsigned char *)
paramPtr->output.buf, paramPtr->output.toWrite);
+ Tcl_Preserve(rcPtr);
if (InvokeTclMethod(rcPtr, "write", bufObj, NULL, &resObj) != TCL_OK) {
int code = ErrnoReturn(rcPtr, resObj);
@@ -2884,6 +2911,7 @@
paramPtr->output.toWrite = written;
}
}
+ Tcl_Release(rcPtr);
break;
}
@@ -2893,6 +2921,7 @@
(paramPtr->seek.seekMode==SEEK_SET) ? "start" :
(paramPtr->seek.seekMode==SEEK_CUR) ? "current" : "end", -1);
+ Tcl_Preserve(rcPtr);
if (InvokeTclMethod(rcPtr, "seek", offObj, baseObj, &resObj)!=TCL_OK){
ForwardSetObjError(paramPtr, resObj);
paramPtr->seek.offset = -1;
@@ -2916,24 +2945,29 @@
paramPtr->seek.offset = -1;
}
}
+ Tcl_Release(rcPtr);
break;
}
case ForwardedWatch: {
Tcl_Obj *maskObj = DecodeEventMask(paramPtr->watch.mask);
+ Tcl_Preserve(rcPtr);
(void) InvokeTclMethod(rcPtr, "watch", maskObj, NULL, NULL);
Tcl_DecrRefCount(maskObj);
+ Tcl_Release(rcPtr);
break;
}
case ForwardedBlock: {
Tcl_Obj *blockObj = Tcl_NewBooleanObj(!paramPtr->block.nonblocking);
+ Tcl_Preserve(rcPtr);
if (InvokeTclMethod(rcPtr, "blocking", blockObj, NULL,
&resObj) != TCL_OK) {
ForwardSetObjError(paramPtr, resObj);
}
+ Tcl_Release(rcPtr);
break;
}
@@ -2941,10 +2975,12 @@
Tcl_Obj *optionObj = Tcl_NewStringObj(paramPtr->setOpt.name, -1);
Tcl_Obj *valueObj = Tcl_NewStringObj(paramPtr->setOpt.value, -1);
+ Tcl_Preserve(rcPtr);
if (InvokeTclMethod(rcPtr, "configure", optionObj, valueObj,
&resObj) != TCL_OK) {
ForwardSetObjError(paramPtr, resObj);
}
+ Tcl_Release(rcPtr);
break;
}
@@ -2955,12 +2991,14 @@
Tcl_Obj *optionObj = Tcl_NewStringObj(paramPtr->getOpt.name, -1);
+ Tcl_Preserve(rcPtr);
if (InvokeTclMethod(rcPtr, "cget", optionObj, NULL, &resObj)!=TCL_OK){
ForwardSetObjError(paramPtr, resObj);
} else {
Tcl_DStringAppend(paramPtr->getOpt.value,
TclGetString(resObj), -1);
}
+ Tcl_Release(rcPtr);
break;
}
@@ -2969,6 +3007,7 @@
* Retrieve all options.
*/
+ Tcl_Preserve(rcPtr);
if (InvokeTclMethod(rcPtr, "cgetall", NULL, NULL, &resObj) != TCL_OK){
ForwardSetObjError(paramPtr, resObj);
} else {
@@ -3004,6 +3043,7 @@
}
}
}
+ Tcl_Release(rcPtr);
break;
default: