summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2009-06-10 21:39:49 (GMT)
committerdgp <dgp@users.sourceforge.net>2009-06-10 21:39:49 (GMT)
commit6e902e710f444b6f54b6134c61317a4d37a22804 (patch)
tree19cc906f005b23d5be4c300bb0f6c4c9c8742dd2
parent2a3653593e13fea9eee1652863db7b373b0b3fa7 (diff)
downloadtcl-6e902e710f444b6f54b6134c61317a4d37a22804.zip
tcl-6e902e710f444b6f54b6134c61317a4d37a22804.tar.gz
tcl-6e902e710f444b6f54b6134c61317a4d37a22804.tar.bz2
* generic/tclStringObj.c: Revised [format] to not overflow the
integer calculations computing the length of the %ll formats of really big integers. Also added protections so that [format]s that would produce results overflowing the maximum string length of Tcl values throw a normal Tcl error instead of a panic. [Bug 2801413]
-rw-r--r--ChangeLog6
-rw-r--r--generic/tclStringObj.c77
2 files changed, 75 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index d645d55..d3462ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2009-06-10 Don Porter <dgp@users.sourceforge.net>
+ * generic/tclStringObj.c: Revised [format] to not overflow the
+ integer calculations computing the length of the %ll formats of
+ really big integers. Also added protections so that [format]s that
+ would produce results overflowing the maximum string length of Tcl
+ values throw a normal Tcl error instead of a panic. [Bug 2801413]
+
* generic/tclStringObj.c: Corrected failures to deal with the
"pure unicode" representation of an empty string. Thanks to Julian
Noble for reporting the problem. [Bug 2803109]
diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c
index ded77e9..ebc15b3 100644
--- a/generic/tclStringObj.c
+++ b/generic/tclStringObj.c
@@ -33,7 +33,7 @@
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclStringObj.c,v 1.123 2009/06/10 14:44:29 dgp Exp $ */
+ * RCS: @(#) $Id: tclStringObj.c,v 1.124 2009/06/10 21:39:49 dgp Exp $ */
#include "tclInt.h"
#include "tommath.h"
@@ -1659,18 +1659,20 @@ Tcl_AppendFormatToObj(
{
const char *span = format, *msg;
int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
- int originalLength;
+ int originalLength, limit;
static const char *mixedXPG =
"cannot mix \"%\" and \"%n$\" conversion specifiers";
static const char *const badIndex[2] = {
"not enough arguments for all format specifiers",
"\"%n$\" argument index out of range"
};
+ static const char *overflow = "max size for a Tcl value exceeded";
if (Tcl_IsShared(appendObj)) {
Tcl_Panic("%s called with shared object", "Tcl_AppendFormatToObj");
}
TclGetStringFromObj(appendObj, &originalLength);
+ limit = INT_MAX - originalLength;
/*
* Format string is NUL-terminated.
@@ -1680,7 +1682,7 @@ Tcl_AppendFormatToObj(
char *end;
int gotMinus, gotHash, gotZero, gotSpace, gotPlus, sawFlag;
int width, gotPrecision, precision, useShort, useWide, useBig;
- int newXpg, numChars, allocSegment = 0;
+ int newXpg, numChars, allocSegment = 0, segmentLimit, segmentNumBytes;
Tcl_Obj *segment;
Tcl_UniChar ch;
int step = Tcl_UtfToUniChar(format, &ch);
@@ -1691,7 +1693,12 @@ Tcl_AppendFormatToObj(
continue;
}
if (numBytes) {
+ if (numBytes > limit) {
+ msg = overflow;
+ goto errorMsg;
+ }
Tcl_AppendToObj(appendObj, span, numBytes);
+ limit -= numBytes;
numBytes = 0;
}
@@ -1798,6 +1805,10 @@ Tcl_AppendFormatToObj(
format += step;
step = Tcl_UtfToUniChar(format, &ch);
}
+ if (width > limit) {
+ msg = overflow;
+ goto errorMsg;
+ }
/*
* Step 4. Precision.
@@ -1911,7 +1922,7 @@ Tcl_AppendFormatToObj(
long l;
Tcl_WideInt w;
mp_int big;
- int isNegative = 0;
+ int toAppend, isNegative = 0;
if (useBig) {
if (Tcl_GetBignumFromObj(interp, segment, &big) != TCL_OK) {
@@ -1962,25 +1973,30 @@ Tcl_AppendFormatToObj(
segment = Tcl_NewObj();
allocSegment = 1;
+ segmentLimit = INT_MAX;
Tcl_IncrRefCount(segment);
if ((isNegative || gotPlus || gotSpace) && (useBig || ch=='d')) {
Tcl_AppendToObj(segment,
(isNegative ? "-" : gotPlus ? "+" : " "), 1);
+ segmentLimit -= 1;
}
if (gotHash) {
switch (ch) {
case 'o':
Tcl_AppendToObj(segment, "0", 1);
+ segmentLimit -= 1;
precision--;
break;
case 'x':
case 'X':
Tcl_AppendToObj(segment, "0x", 2);
+ segmentLimit -= 2;
break;
case 'b':
Tcl_AppendToObj(segment, "0b", 2);
+ segmentLimit -= 2;
break;
}
}
@@ -2011,6 +2027,7 @@ Tcl_AppendFormatToObj(
length--;
bytes++;
}
+ toAppend = length;
/*
* Canonical decimal string reps for integers are composed
@@ -2019,6 +2036,9 @@ Tcl_AppendFormatToObj(
*/
if (gotPrecision) {
+ if (length < precision) {
+ segmentLimit -= (precision - length);
+ }
while (length < precision) {
Tcl_AppendToObj(segment, "0", 1);
length++;
@@ -2027,12 +2047,19 @@ Tcl_AppendFormatToObj(
}
if (gotZero) {
length += Tcl_GetCharLength(segment);
+ if (length < width) {
+ segmentLimit -= (width - length);
+ }
while (length < width) {
Tcl_AppendToObj(segment, "0", 1);
length++;
}
}
- Tcl_AppendToObj(segment, bytes, -1);
+ if (toAppend > segmentLimit) {
+ msg = overflow;
+ goto errorMsg;
+ }
+ Tcl_AppendToObj(segment, bytes, toAppend);
Tcl_DecrRefCount(pure);
break;
}
@@ -2043,7 +2070,8 @@ Tcl_AppendFormatToObj(
case 'X':
case 'b': {
Tcl_WideUInt bits = (Tcl_WideUInt)0;
- int length, numBits = 4, numDigits = 0, base = 16;
+ Tcl_WideInt numDigits = (Tcl_WideInt)0;
+ int length, numBits = 4, base = 16;
int index = 0, shift = 0;
Tcl_Obj *pure;
char *bytes;
@@ -2077,11 +2105,16 @@ Tcl_AppendFormatToObj(
int leftover = (big.used * DIGIT_BIT) % numBits;
mp_digit mask = (~(mp_digit)0) << (DIGIT_BIT-leftover);
- numDigits = 1 + ((big.used * DIGIT_BIT) / numBits);
+ numDigits = 1 +
+ (((Tcl_WideInt)big.used * DIGIT_BIT) / numBits);
while ((mask & big.dp[big.used-1]) == 0) {
numDigits--;
mask >>= numBits;
}
+ if (numDigits > INT_MAX) {
+ msg = overflow;
+ goto errorMsg;
+ }
} else if (!useBig) {
unsigned long int ul = (unsigned long int) l;
@@ -2102,7 +2135,7 @@ Tcl_AppendFormatToObj(
pure = Tcl_NewObj();
Tcl_SetObjLength(pure, numDigits);
bytes = TclGetString(pure);
- length = numDigits;
+ toAppend = length = numDigits;
while (numDigits--) {
int digitOffset;
@@ -2126,6 +2159,9 @@ Tcl_AppendFormatToObj(
mp_clear(&big);
}
if (gotPrecision) {
+ if (length < precision) {
+ segmentLimit -= (precision - length);
+ }
while (length < precision) {
Tcl_AppendToObj(segment, "0", 1);
length++;
@@ -2134,11 +2170,18 @@ Tcl_AppendFormatToObj(
}
if (gotZero) {
length += Tcl_GetCharLength(segment);
+ if (length < width) {
+ segmentLimit -= (width - length);
+ }
while (length < width) {
Tcl_AppendToObj(segment, "0", 1);
length++;
}
}
+ if (toAppend > segmentLimit) {
+ msg = overflow;
+ goto errorMsg;
+ }
Tcl_AppendObjToObj(segment, pure);
Tcl_DecrRefCount(pure);
break;
@@ -2222,15 +2265,28 @@ Tcl_AppendFormatToObj(
numChars = Tcl_GetCharLength(segment);
if (!gotMinus) {
+ if (numChars < width) {
+ limit -= (width - numChars);
+ }
while (numChars < width) {
Tcl_AppendToObj(appendObj, (gotZero ? "0" : " "), 1);
numChars++;
}
}
+
+ Tcl_GetStringFromObj(segment, &segmentNumBytes);
+ if (segmentNumBytes > limit) {
+ msg = overflow;
+ goto errorMsg;
+ }
Tcl_AppendObjToObj(appendObj, segment);
+ limit -= segmentNumBytes;
if (allocSegment) {
Tcl_DecrRefCount(segment);
}
+ if (numChars < width) {
+ limit -= (width - numChars);
+ }
while (numChars < width) {
Tcl_AppendToObj(appendObj, (gotZero ? "0" : " "), 1);
numChars++;
@@ -2239,7 +2295,12 @@ Tcl_AppendFormatToObj(
objIndex += gotSequential;
}
if (numBytes) {
+ if (numBytes > limit) {
+ msg = overflow;
+ goto errorMsg;
+ }
Tcl_AppendToObj(appendObj, span, numBytes);
+ limit -= numBytes;
numBytes = 0;
}