Index: generic/tclStringObj.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclStringObj.c,v
retrieving revision 1.123
diff -u -r1.123 tclStringObj.c
--- generic/tclStringObj.c	10 Jun 2009 14:44:29 -0000	1.123
+++ generic/tclStringObj.c	10 Jun 2009 21:20:55 -0000
@@ -1659,18 +1659,20 @@
 {
     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 @@
 	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 @@
 	    continue;
 	}
 	if (numBytes) {
+	    if (numBytes > limit) {
+		msg = overflow;
+		goto errorMsg;
+	    }
 	    Tcl_AppendToObj(appendObj, span, numBytes);
+	    limit -= numBytes;
 	    numBytes = 0;
 	}
 
@@ -1798,6 +1805,10 @@
 	    format += step;
 	    step = Tcl_UtfToUniChar(format, &ch);
 	}
+	if (width > limit) {
+	    msg = overflow;
+	    goto errorMsg;
+	}
 
 	/*
 	 * Step 4. Precision.
@@ -1911,7 +1922,7 @@
 	    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 @@
 
 	    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 @@
 		    length--;
 		    bytes++;
 		}
+		toAppend = length;
 
 		/*
 		 * Canonical decimal string reps for integers are composed
@@ -2019,6 +2036,9 @@
 		 */
 
 		if (gotPrecision) {
+		    if (length < precision) {
+			segmentLimit -= (precision - length);
+		    }
 		    while (length < precision) {
 			Tcl_AppendToObj(segment, "0", 1);
 			length++;
@@ -2027,12 +2047,19 @@
 		}
 		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 @@
 	    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 @@
 		    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 @@
 		pure = Tcl_NewObj();
 		Tcl_SetObjLength(pure, numDigits);
 		bytes = TclGetString(pure);
-		length = numDigits;
+		toAppend = length = numDigits;
 		while (numDigits--) {
 		    int digitOffset;
 
@@ -2126,6 +2159,9 @@
 		    mp_clear(&big);
 		}
 		if (gotPrecision) {
+		    if (length < precision) {
+			segmentLimit -= (precision - length);
+		    }
 		    while (length < precision) {
 			Tcl_AppendToObj(segment, "0", 1);
 			length++;
@@ -2134,11 +2170,18 @@
 		}
 		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 @@
 
 	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 @@
 	objIndex += gotSequential;
     }
     if (numBytes) {
+	if (numBytes > limit) {
+	    msg = overflow;
+	    goto errorMsg;
+	}
 	Tcl_AppendToObj(appendObj, span, numBytes);
+	limit -= numBytes;
 	numBytes = 0;
     }
 
