summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_string.py26
-rw-r--r--Lib/test/test_unicode.py25
-rw-r--r--Objects/stringobject.c22
-rw-r--r--Objects/unicodeobject.c31
4 files changed, 88 insertions, 16 deletions
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_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
+
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 @@ 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...')
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 @@ 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);
}
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 @@ 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);
}