summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorpooryorick <com.digitalsmarties@pooryorick.com>2023-03-15 08:42:11 (GMT)
committerpooryorick <com.digitalsmarties@pooryorick.com>2023-03-15 08:42:11 (GMT)
commit6ded4b92be27dd73c424f6d524d1a0578621c126 (patch)
tree09a62f08296aed51fd26d12c1202a186b40bf6fe /generic
parent6cf4a0dea38321c52fdcbe73f72f99f4f444bc75 (diff)
downloadtcl-6ded4b92be27dd73c424f6d524d1a0578621c126.zip
tcl-6ded4b92be27dd73c424f6d524d1a0578621c126.tar.gz
tcl-6ded4b92be27dd73c424f6d524d1a0578621c126.tar.bz2
Further fix for issue [ea69b0258a9833cb], crash when using a channel transformation on TCP client socket.
Diffstat (limited to 'generic')
-rw-r--r--generic/tclIO.c52
-rw-r--r--generic/tclIO.h3
2 files changed, 39 insertions, 16 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 58137a5..08c52a7 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -165,6 +165,7 @@ static int CheckForDeadChannel(Tcl_Interp *interp,
static void CheckForStdChannelsBeingClosed(Tcl_Channel chan);
static void CleanupChannelHandlers(Tcl_Interp *interp,
Channel *chanPtr);
+static void CleanupTimerHandler(ChannelState *statePtr);
static int CloseChannel(Tcl_Interp *interp, Channel *chanPtr,
int errorCode);
static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr,
@@ -172,6 +173,7 @@ static int CloseChannelPart(Tcl_Interp *interp, Channel *chanPtr,
static int CloseWrite(Tcl_Interp *interp, Channel *chanPtr);
static void CommonGetsCleanup(Channel *chanPtr);
static int CopyData(CopyState *csPtr, int mask);
+static void DeleteTimerHandler(ChannelState *statePtr);
static int MoveBytes(CopyState *csPtr);
static void MBCallback(CopyState *csPtr, Tcl_Obj *errObj);
@@ -1730,6 +1732,7 @@ Tcl_CreateChannel(
statePtr->scriptRecordPtr = NULL;
statePtr->bufSize = CHANNELBUFFER_DEFAULT_SIZE;
statePtr->timer = NULL;
+ statePtr->timerChanPtr = NULL;
statePtr->csPtrR = NULL;
statePtr->csPtrW = NULL;
statePtr->outputStage = NULL;
@@ -3187,8 +3190,8 @@ CloseChannel(
/*
* Cancel any outstanding timer.
*/
+ DeleteTimerHandler(statePtr);
- Tcl_DeleteTimerHandler(statePtr->timer);
/*
* Mark the channel as deleted by clearing the type structure.
@@ -3540,7 +3543,7 @@ Tcl_Close(
/*
* Cancel any outstanding timer.
*/
- Tcl_DeleteTimerHandler(statePtr->timer);
+ DeleteTimerHandler(statePtr);
/*
* Invoke the registered close callbacks and delete their records.
@@ -4015,8 +4018,7 @@ Tcl_ClearChannelHandlers(
/*
* Cancel any outstanding timer.
*/
-
- Tcl_DeleteTimerHandler(statePtr->timer);
+ DeleteTimerHandler(statePtr);
/*
* Remove any references to channel handlers for this channel that may be
@@ -8805,8 +8807,9 @@ UpdateInterest(
if (!statePtr->timer) {
TclChannelPreserve((Tcl_Channel)chanPtr);
+ statePtr->timerChanPtr = chanPtr;
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
- ChannelTimerProc, chanPtr);
+ ChannelTimerProc, chanPtr);
}
}
}
@@ -8816,6 +8819,7 @@ UpdateInterest(
&& GotFlag(statePtr, CHANNEL_NONBLOCKING)) {
TclChannelPreserve((Tcl_Channel)chanPtr);
+ statePtr->timerChanPtr = chanPtr;
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
ChannelTimerProc,chanPtr);
}
@@ -8846,7 +8850,6 @@ ChannelTimerProc(
void *clientData)
{
Channel *chanPtr = (Channel *)clientData;
-
/* State info for channel */
ChannelState *statePtr = chanPtr->state;
@@ -8857,7 +8860,7 @@ ChannelTimerProc(
*/
if (chanPtr->typePtr == NULL) {
- TclChannelRelease((Tcl_Channel)chanPtr);
+ CleanupTimerHandler(statePtr);
} else {
Tcl_Preserve(statePtr);
statePtr->timer = NULL;
@@ -8870,35 +8873,52 @@ ChannelTimerProc(
* before UpdateInterest gets called by Tcl_NotifyChannel.
*/
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
- ChannelTimerProc,chanPtr);
+ ChannelTimerProc,chanPtr);
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_WRITABLE);
} else {
/* The channel may have just been closed from within Tcl_NotifyChannel */
if (!GotFlag(statePtr, CHANNEL_INCLOSE)) {
if (!GotFlag(statePtr, CHANNEL_NEED_MORE_DATA)
- && (statePtr->interestMask & TCL_READABLE)
- && (statePtr->inQueueHead != NULL)
- && IsBufferReady(statePtr->inQueueHead)) {
+ && (statePtr->interestMask & TCL_READABLE)
+ && (statePtr->inQueueHead != NULL)
+ && IsBufferReady(statePtr->inQueueHead)) {
/*
* Restart the timer in case a channel handler reenters the event loop
* before UpdateInterest gets called by Tcl_NotifyChannel.
*/
statePtr->timer = Tcl_CreateTimerHandler(SYNTHETIC_EVENT_TIME,
- ChannelTimerProc,chanPtr);
+ ChannelTimerProc,chanPtr);
Tcl_NotifyChannel((Tcl_Channel) chanPtr, TCL_READABLE);
} else {
- TclChannelRelease((Tcl_Channel)chanPtr);
+ CleanupTimerHandler(statePtr);
UpdateInterest(chanPtr);
}
} else {
- TclChannelRelease((Tcl_Channel)chanPtr);
+ CleanupTimerHandler(statePtr);
}
}
-
Tcl_Release(statePtr);
}
-
+}
+
+static void
+DeleteTimerHandler(
+ ChannelState *statePtr
+)
+{
+ if (statePtr->timer != NULL) {
+ Tcl_DeleteTimerHandler(statePtr->timer);
+ CleanupTimerHandler(statePtr);
+ }
+}
+static void
+CleanupTimerHandler(
+ ChannelState *statePtr
+){
+ TclChannelRelease((Tcl_Channel)statePtr->timerChanPtr);
+ statePtr->timer = NULL;
+ statePtr->timerChanPtr = NULL;
}
/*
diff --git a/generic/tclIO.h b/generic/tclIO.h
index 689067f..bfaf416 100644
--- a/generic/tclIO.h
+++ b/generic/tclIO.h
@@ -188,6 +188,9 @@ typedef struct ChannelState {
* handlers ("fileevent") on this channel. */
Tcl_Size bufSize; /* What size buffers to allocate? */
Tcl_TimerToken timer; /* Handle to wakeup timer for this channel. */
+ Channel *timerChanPtr; /* Needed in order to decrement the refCount of
+ the right channel when the timer is
+ deleted. */
struct CopyState *csPtrR; /* State of background copy for which channel
* is input, or NULL. */
struct CopyState *csPtrW; /* State of background copy for which channel