summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/tclStringObj.c76
1 files changed, 68 insertions, 8 deletions
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;
}