summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2009-10-19 21:59:17 (GMT)
committerdgp <dgp@users.sourceforge.net>2009-10-19 21:59:17 (GMT)
commitef2ad353d74da54fe55bed15a320b667774cb790 (patch)
treebf533de31e429fe873d4937760b81b135cb5a40c
parent7b94da051e6dde67f1a1602c93fffbcc98787cf1 (diff)
downloadtcl-ef2ad353d74da54fe55bed15a320b667774cb790.zip
tcl-ef2ad353d74da54fe55bed15a320b667774cb790.tar.gz
tcl-ef2ad353d74da54fe55bed15a320b667774cb790.tar.bz2
* generic/tclIO.c: Revised ReadChars and FilterInputBytes routines
to permit reads to continue up to the string limits of Tcl values. Before revisions, large read attempts could panic when as little as half the limiting value length was reached. [Patch 2107634] Thanks to Sean Morrison and Bob Parker for their roles in the fix.
-rw-r--r--ChangeLog8
-rw-r--r--generic/tclIO.c44
2 files changed, 35 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index 3b4a3f9..609b273 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2009-10-19 Don Porter <dgp@users.sourceforge.net>
+
+ * generic/tclIO.c: Revised ReadChars and FilterInputBytes routines
+ to permit reads to continue up to the string limits of Tcl values.
+ Before revisions, large read attempts could panic when as little as
+ half the limiting value length was reached. [Patch 2107634]
+ Thanks to Sean Morrison and Bob Parker for their roles in the fix.
+
2009-10-18 Joe Mistachkin <joe@mistachkin.com>
* tests/thread.test (thread-4.[345]): [Bug 1565466]: Correct tests to
diff --git a/generic/tclIO.c b/generic/tclIO.c
index 649e31b..a74cd04 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -10,7 +10,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIO.c,v 1.137.2.11 2009/07/24 16:51:28 andreas_kupries Exp $
+ * RCS: @(#) $Id: tclIO.c,v 1.137.2.12 2009/10/19 21:59:18 dgp Exp $
*/
#include "tclInt.h"
@@ -4613,7 +4613,7 @@ FilterInputBytes(
/* State info for channel */
ChannelBuffer *bufPtr;
char *raw, *rawStart, *dst;
- int offset, toRead, dstNeeded, spaceLeft, result, rawLen, length;
+ int offset, toRead, dstNeeded, spaceLeft, result, rawLen;
Tcl_Obj *objPtr;
#define ENCODING_LINESIZE 20 /* Lower bound on how many bytes to convert at
* a time. Since we don't know a priori how
@@ -4679,15 +4679,19 @@ FilterInputBytes(
if (toRead > rawLen) {
toRead = rawLen;
}
- dstNeeded = toRead * TCL_UTF_MAX + 1;
- spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1;
+ dstNeeded = toRead * TCL_UTF_MAX;
+ spaceLeft = objPtr->length - offset;
if (dstNeeded > spaceLeft) {
- length = offset * 2;
- if (offset < dstNeeded) {
+ int length = offset + ((offset < dstNeeded) ? dstNeeded : offset);
+
+ if (Tcl_AttemptSetObjLength(objPtr, length) == 0) {
length = offset + dstNeeded;
+ if (Tcl_AttemptSetObjLength(objPtr, length) == 0) {
+ dstNeeded = TCL_UTF_MAX - 1 + toRead;
+ length = offset + dstNeeded;
+ Tcl_SetObjLength(objPtr, length);
+ }
}
- length += TCL_UTF_MAX + 1;
- Tcl_SetObjLength(objPtr, length);
spaceLeft = length - offset;
dst = objPtr->bytes + offset;
*gsPtr->dstPtr = dst;
@@ -4695,7 +4699,7 @@ FilterInputBytes(
gsPtr->state = statePtr->inputEncodingState;
result = Tcl_ExternalToUtf(NULL, gsPtr->encoding, raw, rawLen,
statePtr->inputEncodingFlags, &statePtr->inputEncodingState,
- dst, spaceLeft, &gsPtr->rawRead, &gsPtr->bytesWrote,
+ dst, spaceLeft+1, &gsPtr->rawRead, &gsPtr->bytesWrote,
&gsPtr->charsWrote);
/*
@@ -5419,6 +5423,8 @@ ReadBytes(
* 'charsToRead' can safely be a very large number because space is only
* allocated to hold data read from the channel as needed.
*
+ * 'charsToRead' may *not* be 0.
+ *
* Results:
* The return value is the number of characters appended to the object,
* *offsetPtr is filled with the number of bytes that were appended, and
@@ -5456,7 +5462,7 @@ ReadChars(
* UTF-8. On output, contains another guess
* based on the data seen so far. */
{
- int toRead, factor, offset, spaceLeft, length, srcLen, dstNeeded;
+ int toRead, factor, offset, spaceLeft, srcLen, dstNeeded;
int srcRead, dstWrote, numChars, dstRead;
ChannelBuffer *bufPtr;
char *src, *dst;
@@ -5481,8 +5487,8 @@ ReadChars(
* how many characters were produced by the previous pass.
*/
- dstNeeded = toRead * factor / UTF_EXPANSION_FACTOR;
- spaceLeft = objPtr->length - offset - TCL_UTF_MAX - 1;
+ dstNeeded = TCL_UTF_MAX - 1 + toRead * factor / UTF_EXPANSION_FACTOR;
+ spaceLeft = objPtr->length - offset;
if (dstNeeded > spaceLeft) {
/*
@@ -5491,13 +5497,17 @@ ReadChars(
* larger.
*/
- length = offset * 2;
- if (offset < dstNeeded) {
+ int length = offset + ((offset < dstNeeded) ? dstNeeded : offset);
+
+ if (Tcl_AttemptSetObjLength(objPtr, length) == 0) {
length = offset + dstNeeded;
+ if (Tcl_AttemptSetObjLength(objPtr, length) == 0) {
+ dstNeeded = TCL_UTF_MAX - 1 + toRead;
+ length = offset + dstNeeded;
+ Tcl_SetObjLength(objPtr, length);
+ }
}
spaceLeft = length - offset;
- length += TCL_UTF_MAX + 1;
- Tcl_SetObjLength(objPtr, length);
}
if (toRead == srcLen) {
/*
@@ -5589,7 +5599,7 @@ ReadChars(
Tcl_ExternalToUtf(NULL, statePtr->encoding, src, srcLen,
statePtr->inputEncodingFlags, &statePtr->inputEncodingState, dst,
- dstNeeded + TCL_UTF_MAX, &srcRead, &dstWrote, &numChars);
+ dstNeeded + 1, &srcRead, &dstWrote, &numChars);
if (encEndFlagSuppressed) {
statePtr->inputEncodingFlags |= TCL_ENCODING_END;