summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--generic/tclIO.c44
2 files changed, 35 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index f3b82ae..18b8933 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>
* 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;