summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2009-06-10 21:38:13 (GMT)
committerdgp <dgp@users.sourceforge.net>2009-06-10 21:38:13 (GMT)
commit855a348eeae253e6765ea3edf689e41d79a7c081 (patch)
tree71bcf4c7619445d232514fcfe54efc942d06cc93
parent84b4642f23e9ce612ea65bb135c9ffadfe21352d (diff)
downloadtcl-855a348eeae253e6765ea3edf689e41d79a7c081.zip
tcl-855a348eeae253e6765ea3edf689e41d79a7c081.tar.gz
tcl-855a348eeae253e6765ea3edf689e41d79a7c081.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--ChangeLog10
-rw-r--r--generic/tclStringObj.c76
2 files changed, 77 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index fb2f2b3..de8d594 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +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]
+
2006-06-09 Kevin B. Kenny <kennykb@acm.org>
* generic/tclGetDate.y: Fixed a thread safety bug in the generated
@@ -13,7 +21,7 @@
* library/tzdata/Asia/Dhaka: New DST rule for Bangladesh.
(Olson's tzdata2009i.)
-
+
2009-06-02 Don Porter <dgp@users.sourceforge.net>
* generic/tclExecute.c: Replace dynamically-initialized table with
diff --git a/generic/tclStringObj.c b/generic/tclStringObj.c
index a0992aa..e844e14 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.70.2.12 2009/04/15 19:07:04 dgp Exp $ */
+ * RCS: @(#) $Id: tclStringObj.c,v 1.70.2.13 2009/06/10 21:38:13 dgp Exp $ */
#include "tclInt.h"
#include "tommath.h"
@@ -1800,18 +1800,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 *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.
@@ -1821,7 +1823,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);
@@ -1832,7 +1834,12 @@ Tcl_AppendFormatToObj(
continue;
}
if (numBytes) {
+ if (numBytes > limit) {
+ msg = overflow;
+ goto errorMsg;
+ }
Tcl_AppendToObj(appendObj, span, numBytes);
+ limit -= numBytes;
numBytes = 0;
}
@@ -1939,6 +1946,10 @@ Tcl_AppendFormatToObj(
format += step;
step = Tcl_UtfToUniChar(format, &ch);
}
+ if (width > limit) {
+ msg = overflow;
+ goto errorMsg;
+ }
/*
* Step 4. Precision.
@@ -2051,7 +2062,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) {
@@ -2102,21 +2113,25 @@ 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;
}
}
@@ -2147,6 +2162,7 @@ Tcl_AppendFormatToObj(
length--;
bytes++;
}
+ toAppend = length;
/*
* Canonical decimal string reps for integers are composed
@@ -2155,6 +2171,9 @@ Tcl_AppendFormatToObj(
*/
if (gotPrecision) {
+ if (length < precision) {
+ segmentLimit -= (precision - length);
+ }
while (length < precision) {
Tcl_AppendToObj(segment, "0", 1);
length++;
@@ -2163,12 +2182,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;
}
@@ -2178,7 +2204,8 @@ Tcl_AppendFormatToObj(
case 'x':
case 'X': {
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;
@@ -2210,11 +2237,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;
@@ -2235,7 +2267,7 @@ Tcl_AppendFormatToObj(
pure = Tcl_NewObj();
Tcl_SetObjLength(pure, numDigits);
bytes = TclGetString(pure);
- length = numDigits;
+ toAppend = length = numDigits;
while (numDigits--) {
int digitOffset;
@@ -2259,6 +2291,9 @@ Tcl_AppendFormatToObj(
mp_clear(&big);
}
if (gotPrecision) {
+ if (length < precision) {
+ segmentLimit -= (precision - length);
+ }
while (length < precision) {
Tcl_AppendToObj(segment, "0", 1);
length++;
@@ -2267,11 +2302,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;
@@ -2355,15 +2397,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++;
@@ -2372,7 +2427,12 @@ Tcl_AppendFormatToObj(
objIndex += gotSequential;
}
if (numBytes) {
+ if (numBytes > limit) {
+ msg = overflow;
+ goto errorMsg;
+ }
Tcl_AppendToObj(appendObj, span, numBytes);
+ limit -= numBytes;
numBytes = 0;
}