diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | generic/tclIO.c | 44 |
2 files changed, 35 insertions, 17 deletions
@@ -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> * generic/tclObj.c (TclDbDumpActiveObjects, TclDbInitNewObj) diff --git a/generic/tclIO.c b/generic/tclIO.c index 737e64e..28e9fbc 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.162 2009/09/30 03:11:26 dgp Exp $ + * RCS: @(#) $Id: tclIO.c,v 1.163 2009/10/19 22:00:19 dgp Exp $ */ #include "tclInt.h" @@ -5016,7 +5016,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 @@ -5082,15 +5082,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; @@ -5098,7 +5102,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); /* @@ -5817,6 +5821,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 @@ -5854,7 +5860,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; @@ -5879,8 +5885,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) { /* @@ -5889,13 +5895,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) { /* @@ -5987,7 +5997,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; |