Patch for bug #659709: bogus computation of float length

Python 2.2.x backport candidate. (This bug has been around since
Python 1.6.)
diff --git a/Lib/test/test_string.py b/Lib/test/test_string.py
index a30cdbd..6361f78 100644
--- a/Lib/test/test_string.py
+++ b/Lib/test/test_string.py
@@ -57,3 +57,29 @@
 string.whitespace
 string.lowercase
 string.uppercase
+
+# Float formatting
+for prec in range(100):
+    formatstring = u'%%.%if' % prec
+    value = 0.01
+    for x in range(60):
+        value = value * 3.141592655 / 3.0 * 10.0
+        #print 'Overflow check for x=%i and prec=%i:' % \
+        #      (x, prec),
+        try:
+            result = formatstring % value
+        except OverflowError:
+            # The formatfloat() code in stringobject.c and
+            # unicodeobject.c uses a 120 byte buffer and switches from
+            # 'f' formatting to 'g' at precision 50, so we expect
+            # OverflowErrors for the ranges x < 50 and prec >= 67.
+            if x >= 50 or \
+               prec < 67:
+                print '*** unexpected OverflowError for x=%i and prec=%i' % (x, prec)
+            else:
+                #print 'OverflowError'
+                pass
+        else:
+            #print result
+            pass
+    
diff --git a/Lib/test/test_unicode.py b/Lib/test/test_unicode.py
index 66a7f91..2a94586 100644
--- a/Lib/test/test_unicode.py
+++ b/Lib/test/test_unicode.py
@@ -476,6 +476,31 @@
     else:
         print '*** formatting u"%%c" %% %i should give a ValueError' % ordinal
 
+# float formatting
+for prec in range(100):
+    formatstring = u'%%.%if' % prec
+    value = 0.01
+    for x in range(60):
+        value = value * 3.141592655 / 3.0 * 10.0
+        #print 'Overflow check for x=%i and prec=%i:' % \
+        #      (x, prec),
+        try:
+            result = formatstring % value
+        except OverflowError:
+            # The formatfloat() code in stringobject.c and
+            # unicodeobject.c uses a 120 byte buffer and switches from
+            # 'f' formatting to 'g' at precision 50, so we expect
+            # OverflowErrors for the ranges x < 50 and prec >= 67.
+            if x >= 50 or \
+               prec < 67:
+                print '*** unexpected OverflowError for x=%i and prec=%i' % (x, prec)
+            else:
+                #print 'OverflowError'
+                pass
+        else:
+            #print result
+            pass
+    
 # formatting jobs delegated from the string implementation:
 verify('...%(foo)s...' % {'foo':u"abc"} == u'...abc...')
 verify('...%(foo)s...' % {'foo':"abc"} == '...abc...')
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index 1e42856..748592e 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -3361,21 +3361,31 @@
 		prec = 6;
 	if (type == 'f' && fabs(x)/1e25 >= 1e25)
 		type = 'g';
-	PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c",
-		      (flags&F_ALT) ? "#" : "",
-		      prec, type);
-	/* worst case length calc to ensure no buffer overrun:
+	/* Worst case length calc to ensure no buffer overrun:
+
+	   'g' formats:
 	     fmt = %#.<prec>g
 	     buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
 	        for any double rep.)
 	     len = 1 + prec + 1 + 2 + 5 = 9 + prec
+
+	   'f' formats:
+	     buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50)
+	     len = 1 + 50 + 1 + prec = 52 + prec
+
 	   If prec=0 the effective precision is 1 (the leading digit is
-	   always given), therefore increase by one to 10+prec. */
-	if (buflen <= (size_t)10 + (size_t)prec) {
+	   always given), therefore increase the length by one. 
+
+	*/
+	if ((type == 'g' && buflen <= (size_t)10 + (size_t)prec) ||
+	    (type == 'f' && buflen <= (size_t)53 + (size_t)prec)) {
 		PyErr_SetString(PyExc_OverflowError,
 			"formatted float is too long (precision too large?)");
 		return -1;
 	}
+	PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c",
+		      (flags&F_ALT) ? "#" : "",
+		      prec, type);
 	PyOS_snprintf(buf, buflen, fmt, x);
 	return strlen(buf);
 }
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 8565fb1..8dcec51 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -5999,20 +5999,31 @@
 	prec = 6;
     if (type == 'f' && (fabs(x) / 1e25) >= 1e25)
 	type = 'g';
-    PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c",
-		  (flags & F_ALT) ? "#" : "", prec, type);
-    /* worst case length calc to ensure no buffer overrun:
-         fmt = %#.<prec>g
-         buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
-            for any double rep.)
-         len = 1 + prec + 1 + 2 + 5 = 9 + prec
+    /* Worst case length calc to ensure no buffer overrun:
+
+       'g' formats:
+	 fmt = %#.<prec>g
+	 buf = '-' + [0-9]*prec + '.' + 'e+' + (longest exp
+	    for any double rep.)
+	 len = 1 + prec + 1 + 2 + 5 = 9 + prec
+
+       'f' formats:
+	 buf = '-' + [0-9]*x + '.' + [0-9]*prec (with x < 50)
+	 len = 1 + 50 + 1 + prec = 52 + prec
+
        If prec=0 the effective precision is 1 (the leading digit is
-       always given), therefore increase by one to 10+prec. */
-    if (buflen <= (size_t)10 + (size_t)prec) {
+       always given), therefore increase the length by one. 
+
+    */
+    if ((type == 'g' && buflen <= (size_t)10 + (size_t)prec) ||
+	(type == 'f' && buflen <= (size_t)53 + (size_t)prec)) {
 	PyErr_SetString(PyExc_OverflowError,
-	    "formatted float is too long (precision too long?)");
+			"formatted float is too long (precision too large?)");
 	return -1;
     }
+    PyOS_snprintf(fmt, sizeof(fmt), "%%%s.%d%c",
+		  (flags&F_ALT) ? "#" : "",
+		  prec, type);
     return usprintf(buf, fmt, x);
 }