From 46e63b3be5cb5ce16dd97cc9f4c17481a5c2f0c8 Mon Sep 17 00:00:00 2001 From: pooryorick Date: Wed, 20 Apr 2022 12:08:45 +0000 Subject: Fix for [a12ad5c4bd7efcf2], buffer allocation on every call to Write(). --- generic/tclIO.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/generic/tclIO.c b/generic/tclIO.c index aa0a5a6..b504369 100644 --- a/generic/tclIO.c +++ b/generic/tclIO.c @@ -2711,6 +2711,7 @@ FlushChannel( int wroteSome = 0; /* Set to one if any data was written to the * driver. */ + int bufExists; /* * Prevent writing on a dead channel -- a channel that has been closed but * not yet deallocated. This can occur if the exit handler for the channel @@ -2879,8 +2880,8 @@ FlushChannel( * queued. */ - DiscardOutputQueued(statePtr); ReleaseChannelBuffer(bufPtr); + DiscardOutputQueued(statePtr); break; } else { /* @@ -2891,20 +2892,32 @@ FlushChannel( wroteSome = 1; } - bufPtr->nextRemoved += written; + bufExists = bufPtr->refCount > 1; + ReleaseChannelBuffer(bufPtr); + if (bufExists) { + /* There is still a reference to this buffer other than the one + * this routine just released, meaning that final cleanup of the + * buffer hasn't been ordered by, e.g. by a reflected channel + * closing the channel from within one of its handler scripts (not + * something one would expecte, but it must be considered). Normal + * operations on the buffer can proceed. + */ - /* - * If this buffer is now empty, recycle it. - */ + bufPtr->nextRemoved += written; - if (IsBufferEmpty(bufPtr)) { - statePtr->outQueueHead = bufPtr->nextPtr; - if (statePtr->outQueueHead == NULL) { - statePtr->outQueueTail = NULL; + /* + * If this buffer is now empty, recycle it. + */ + + if (IsBufferEmpty(bufPtr)) { + statePtr->outQueueHead = bufPtr->nextPtr; + if (statePtr->outQueueHead == NULL) { + statePtr->outQueueTail = NULL; + } + RecycleBuffer(statePtr, bufPtr, 0); } - RecycleBuffer(statePtr, bufPtr, 0); } - ReleaseChannelBuffer(bufPtr); + } /* Closes "while". */ /* @@ -6957,15 +6970,17 @@ GetInput( PreserveChannelBuffer(bufPtr); nread = ChanRead(chanPtr, InsertPoint(bufPtr), toRead); + ReleaseChannelBuffer(bufPtr); if (nread < 0) { result = Tcl_GetErrno(); } else { result = 0; - bufPtr->nextAdded += nread; + if (statePtr->inQueueTail != NULL) { + statePtr->inQueueTail->nextAdded += nread; + } } - ReleaseChannelBuffer(bufPtr); return result; } -- cgit v0.12