summaryrefslogtreecommitdiffstats
path: root/generic/tclIO.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r--generic/tclIO.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 67264a0..ab8d8ac 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -3189,6 +3189,9 @@ CutChannel(
*/
ChanThreadAction((Channel *) chan, TCL_CHANNEL_THREAD_REMOVE);
+
+ /* Channel is not managed by any thread */
+ statePtr->managingThread = NULL;
}
void
@@ -3233,6 +3236,9 @@ Tcl_CutChannel(
for (; chanPtr != NULL ; chanPtr = chanPtr->upChanPtr) {
ChanThreadAction(chanPtr, TCL_CHANNEL_THREAD_REMOVE);
}
+
+ /* Channel is not managed by any thread */
+ statePtr->managingThread = NULL;
}
/*
@@ -8382,6 +8388,13 @@ Tcl_NotifyChannel(
Tcl_Preserve(statePtr);
/*
+ * Avoid processing if the channel owner has been changed.
+ */
+ if (statePtr->managingThread != Tcl_GetCurrentThread()) {
+ goto done;
+ }
+
+ /*
* If we are flushing in the background, be sure to call FlushChannel for
* writable events. Note that we have to discard the writable event so we
* don't call any write handlers before the flush is complete.
@@ -8415,6 +8428,13 @@ Tcl_NotifyChannel(
} else {
chPtr = chPtr->nextPtr;
}
+
+ /*
+ * Stop if the channel owner has been changed in-between.
+ */
+ if (chanPtr->state->managingThread != Tcl_GetCurrentThread()) {
+ goto done;
+ }
}
/*
@@ -8432,6 +8452,7 @@ Tcl_NotifyChannel(
UpdateInterest(chanPtr);
}
+done:
Tcl_Release(statePtr);
TclChannelRelease(channel);
@@ -8909,6 +8930,11 @@ TclChannelEventScriptInvoker(
interp = esPtr->interp;
/*
+ * Be sure event executed in managed channel (covering bugs similar [f583715154]).
+ */
+ assert(chanPtr->state->managingThread == Tcl_GetCurrentThread());
+
+ /*
* We must preserve the interpreter so we can report errors on it later.
* Note that we do not need to preserve the channel because that is done
* by Tcl_NotifyChannel before calling channel handlers.