diff options
author | dgp <dgp@users.sourceforge.net> | 2009-10-19 21:59:17 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2009-10-19 21:59:17 (GMT) |
commit | ef2ad353d74da54fe55bed15a320b667774cb790 (patch) | |
tree | bf533de31e429fe873d4937760b81b135cb5a40c /generic/tclIO.c | |
parent | 7b94da051e6dde67f1a1602c93fffbcc98787cf1 (diff) | |
download | tcl-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.
Diffstat (limited to 'generic/tclIO.c')
-rw-r--r-- | generic/tclIO.c | 44 |
1 files changed, 27 insertions, 17 deletions
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; |