summaryrefslogtreecommitdiffstats
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
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.
-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;