summaryrefslogtreecommitdiffstats
path: root/generic/tclIO.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2009-10-19 22:00:19 (GMT)
committerdgp <dgp@users.sourceforge.net>2009-10-19 22:00:19 (GMT)
commite6b9dc1ca77df45483a0daaba818bffd3989363e (patch)
tree977976c2fc60a3ced967f3d37b3781aa35076881 /generic/tclIO.c
parent87322cc40198a30c474da4769e08103cb41e7576 (diff)
downloadtcl-e6b9dc1ca77df45483a0daaba818bffd3989363e.zip
tcl-e6b9dc1ca77df45483a0daaba818bffd3989363e.tar.gz
tcl-e6b9dc1ca77df45483a0daaba818bffd3989363e.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.c44
1 files changed, 27 insertions, 17 deletions
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;