]> granicus.if.org Git - python/commitdiff
Patch for bug #659709: bogus computation of float length
authorMarc-André Lemburg <mal@egenix.com>
Sun, 29 Dec 2002 19:44:06 +0000 (19:44 +0000)
committerMarc-André Lemburg <mal@egenix.com>
Sun, 29 Dec 2002 19:44:06 +0000 (19:44 +0000)
Python 2.2.x backport candidate. (This bug has been around since
Python 1.6.)

Lib/test/test_string.py
Lib/test/test_unicode.py
Objects/stringobject.c
Objects/unicodeobject.c

index a30cdbd9c3c2054aad570ec73369134197ac6a0a..6361f786f7d79444700458ebd8722a3877944813 100644 (file)
@@ -57,3 +57,29 @@ string_tests.run_inplace_tests(str)
 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
+    
index 66a7f916c431b7518a18fbf8ef4dd549bd04c63d..2a94586cb9cecece916b6533cb615431128f5297 100644 (file)
@@ -476,6 +476,31 @@ for ordinal in (-100, 0x200000):
     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...')
index 1e4285672949f4e8382d7b7e176cf8fd4dfe956b..748592ea50761818a9c277ed6f77af004dfec0d7 100644 (file)
@@ -3361,21 +3361,31 @@ formatfloat(char *buf, size_t buflen, int flags,
                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);
 }
index 8565fb15454918d16fea3e07d23f31b5122f66f9..8dcec514c73d12d39e3232f36945cb36697ebde9 100644 (file)
@@ -5999,20 +5999,31 @@ formatfloat(Py_UNICODE *buf,
        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);
 }