summaryrefslogtreecommitdiffstats
path: root/generic/tclIO.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2015-09-23 16:29:38 (GMT)
committerdgp <dgp@users.sourceforge.net>2015-09-23 16:29:38 (GMT)
commite52bf0ecd422e64401d71475c5995f18c49c8561 (patch)
tree989556eb66a38ec6eb9c13372dd48ad40f8fb77e /generic/tclIO.c
parentf0f0d2b1abf721e7cae3584cf4fc01cd5e0b9f66 (diff)
parent261ff342b1e18433e104577ad6f8dc7c50f9292a (diff)
downloadtcl-e52bf0ecd422e64401d71475c5995f18c49c8561.zip
tcl-e52bf0ecd422e64401d71475c5995f18c49c8561.tar.gz
tcl-e52bf0ecd422e64401d71475c5995f18c49c8561.tar.bz2
[32ae34e63a] Prevent segfaults and data corruption when CopyData() is called
recursively.
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r--generic/tclIO.c47
1 files changed, 43 insertions, 4 deletions
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 564df27..09b2537 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -113,11 +113,30 @@ typedef struct CopyState {
Tcl_WideInt total; /* Total bytes transferred (written). */
Tcl_Interp *interp; /* Interp that started the copy. */
Tcl_Obj *cmdPtr; /* Command to be invoked at completion. */
+ int refCount; /* Claim count on the struct */
+ int bufInUse; /* Flag to govern access to buffer */
int bufSize; /* Size of appended buffer. */
char buffer[1]; /* Copy buffer, this must be the last
* field. */
} CopyState;
+static void
+PreserveCopyState(
+ CopyState *csPtr)
+{
+ csPtr->refCount++;
+}
+
+static void
+ReleaseCopyState(
+ CopyState *csPtr)
+{
+ if (--csPtr->refCount) {
+ return;
+ }
+ ckfree((char *) csPtr);
+}
+
/*
* All static variables used in this file are collected into a single instance
* of the following structure. For multi-threaded implementations, there is
@@ -8642,9 +8661,13 @@ TclCopyChannel(
Tcl_IncrRefCount(cmdPtr);
}
csPtr->cmdPtr = cmdPtr;
+ csPtr->refCount = 1;
+ csPtr->bufInUse = 0;
inStatePtr->csPtrR = csPtr;
+ PreserveCopyState(csPtr);
outStatePtr->csPtrW = csPtr;
+ PreserveCopyState(csPtr);
/*
* Special handling of -size 0 async transfers, so that the -command is
@@ -8696,6 +8719,11 @@ CopyData(
/* Encoding control */
int underflow; /* Input underflow */
+ if (csPtr->bufInUse) {
+ return TCL_OK;
+ }
+ PreserveCopyState(csPtr);
+
inChan = (Tcl_Channel) csPtr->readPtr;
outChan = (Tcl_Channel) csPtr->writePtr;
inStatePtr = csPtr->readPtr->state;
@@ -8757,6 +8785,7 @@ CopyData(
sizeb = csPtr->toRead;
}
+ csPtr->bufInUse = 1;
if (inBinary || sameEncoding) {
size = DoRead(inStatePtr->topChanPtr, csPtr->buffer, sizeb);
} else {
@@ -8807,6 +8836,7 @@ CopyData(
TclDecrRefCount(bufObj);
bufObj = NULL;
}
+ ReleaseCopyState(csPtr);
return TCL_OK;
}
}
@@ -8827,6 +8857,7 @@ CopyData(
} else {
sizeb = WriteChars(outStatePtr->topChanPtr, buffer, sizeb);
}
+ csPtr->bufInUse = 0;
/*
* [Bug 2895565]. At this point 'size' still contains the number of
@@ -8898,6 +8929,7 @@ CopyData(
TclDecrRefCount(bufObj);
bufObj = NULL;
}
+ ReleaseCopyState(csPtr);
return TCL_OK;
}
@@ -8920,6 +8952,7 @@ CopyData(
TclDecrRefCount(bufObj);
bufObj = NULL;
}
+ ReleaseCopyState(csPtr);
return TCL_OK;
}
} /* while */
@@ -8935,15 +8968,14 @@ CopyData(
*/
total = csPtr->total;
- if (cmdPtr && interp) {
+ if (cmdPtr && interp && csPtr->cmdPtr) {
int code;
/*
* Get a private copy of the command so we can mutate it by adding
* arguments. Note that StopCopy frees our saved reference to the
* original command obj.
*/
-
- cmdPtr = Tcl_DuplicateObj(cmdPtr);
+ cmdPtr = Tcl_DuplicateObj(csPtr->cmdPtr);
Tcl_IncrRefCount(cmdPtr);
StopCopy(csPtr);
Tcl_Preserve(interp);
@@ -8971,6 +9003,7 @@ CopyData(
}
}
}
+ ReleaseCopyState(csPtr);
return result;
}
@@ -9284,10 +9317,16 @@ StopCopy(
CopyEventProc, csPtr);
}
TclDecrRefCount(csPtr->cmdPtr);
+ csPtr->cmdPtr = NULL;
+ }
+ if (inStatePtr->csPtrR == NULL) {
+ return;
}
+ ReleaseCopyState(inStatePtr->csPtrR);
inStatePtr->csPtrR = NULL;
+ ReleaseCopyState(outStatePtr->csPtrW);
outStatePtr->csPtrW = NULL;
- ckfree((char *) csPtr);
+ ReleaseCopyState(csPtr);
}
/*