cpython: 102df748572d (original) (raw)
Mercurial > cpython
changeset 80015:102df748572d 3.2
Issue #14700: Fix buggy overflow checks for large precision and width in new-style and old-style formatting. [#14700]
Mark Dickinson mdickinson@enthought.com | |
---|---|
date | Sun, 28 Oct 2012 10🔞03 +0000 |
parents | 652286ee23f8 |
children | 79ea0c84152a cde4b66699fe |
files | Lib/test/test_unicode.py Misc/NEWS Objects/stringlib/formatter.h Objects/stringlib/string_format.h Objects/unicodeobject.c |
diffstat | 5 files changed, 45 insertions(+), 20 deletions(-)[+] [-] Lib/test/test_unicode.py 27 Misc/NEWS 3 Objects/stringlib/formatter.h 16 Objects/stringlib/string_format.h 15 Objects/unicodeobject.c 4 |
line wrap: on
line diff
--- a/Lib/test/test_unicode.py +++ b/Lib/test/test_unicode.py @@ -906,6 +906,21 @@ class UnicodeTest(string_tests.CommonTes self.assertRaises(ValueError, '{}'.format_map, 'a') self.assertRaises(ValueError, '{a} {}'.format_map, {"a" : 2, "b" : 1})
- def test_format_huge_precision(self):
format_string = ".{}f".format(sys.maxsize + 1)[](#l1.8)
with self.assertRaises(ValueError):[](#l1.9)
result = format(2.34, format_string)[](#l1.10)
- def test_format_huge_width(self):
format_string = "{}f".format(sys.maxsize + 1)[](#l1.13)
with self.assertRaises(ValueError):[](#l1.14)
result = format(2.34, format_string)[](#l1.15)
- def test_format_huge_item_number(self):
format_string = "{{{}:.6f}}".format(sys.maxsize + 1)[](#l1.18)
with self.assertRaises(ValueError):[](#l1.19)
result = format_string.format(2.34)[](#l1.20)
+ def test_format_auto_numbering(self): class C: def init(self, x=100): @@ -990,6 +1005,18 @@ class UnicodeTest(string_tests.CommonTes self.assertEqual('%f' % INF, 'inf') self.assertEqual('%F' % INF, 'INF')
- @support.cpython_only
- def test_formatting_huge_precision(self):
from _testcapi import INT_MAX[](#l1.31)
format_string = "%.{}f".format(INT_MAX + 1)[](#l1.32)
with self.assertRaises(ValueError):[](#l1.33)
result = format_string % 2.34[](#l1.34)
- def test_formatting_huge_width(self):
format_string = "%{}f".format(sys.maxsize + 1)[](#l1.37)
with self.assertRaises(ValueError):[](#l1.38)
result = format_string % 2.34[](#l1.39)
+ def test_startswith_endswith_errors(self): for meth in ('foo'.startswith, 'foo'.endswith): with self.assertRaises(TypeError) as cm:
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.2.4 Core and Builtins ----------------- +- Issue #14700: Fix buggy overflow checks when handling large precisions and
- Issue #6074: Ensure cached bytecode files can always be updated by the user that created them, even when the source file is read-only.
--- a/Objects/stringlib/formatter.h +++ b/Objects/stringlib/formatter.h @@ -73,7 +73,7 @@ static int get_integer(STRINGLIB_CHAR **ptr, STRINGLIB_CHAR *end, Py_ssize_t *result) {
- Py_ssize_t accumulator, digitval; int numdigits; accumulator = numdigits = 0; for (;;(*ptr)++, numdigits++) { @@ -83,19 +83,17 @@ get_integer(STRINGLIB_CHAR *ptr, STRING if (digitval < 0) break; /
This trick was copied from old Unicode format code. It's cute,[](#l3.16)
but would really suck on an old machine with a slow divide[](#l3.17)
implementation. Fortunately, in the normal case we do not[](#l3.18)
expect too many digits.[](#l3.19)
Detect possible overflow before it happens:[](#l3.20)
accumulator * 10 + digitval > PY_SSIZE_T_MAX if and only if[](#l3.22)
accumulator > (PY_SSIZE_T_MAX - digitval) / 10.[](#l3.23) */[](#l3.24)
oldaccumulator = accumulator;[](#l3.25)
accumulator *= 10;[](#l3.26)
if ((accumulator+10)/10 != oldaccumulator+1) {[](#l3.27)
if (accumulator > (PY_SSIZE_T_MAX - digitval) / 10) {[](#l3.28) PyErr_Format(PyExc_ValueError,[](#l3.29) "Too many decimal digits in format string");[](#l3.30) return -1;[](#l3.31) }[](#l3.32)
accumulator += digitval;[](#l3.33)
--- a/Objects/stringlib/string_format.h +++ b/Objects/stringlib/string_format.h @@ -197,7 +197,6 @@ get_integer(const SubString *str) { Py_ssize_t accumulator = 0; Py_ssize_t digitval;
- Py_ssize_t oldaccumulator; STRINGLIB_CHAR p; / empty string is an error */ @@ -209,19 +208,17 @@ get_integer(const SubString str) if (digitval < 0) return -1; /
This trick was copied from old Unicode format code. It's cute,[](#l4.15)
but would really suck on an old machine with a slow divide[](#l4.16)
implementation. Fortunately, in the normal case we do not[](#l4.17)
expect too many digits.[](#l4.18)
Detect possible overflow before it happens:[](#l4.19)
accumulator * 10 + digitval > PY_SSIZE_T_MAX if and only if[](#l4.21)
accumulator > (PY_SSIZE_T_MAX - digitval) / 10.[](#l4.22) */[](#l4.23)
oldaccumulator = accumulator;[](#l4.24)
accumulator *= 10;[](#l4.25)
if ((accumulator+10)/10 != oldaccumulator+1) {[](#l4.26)
if (accumulator > (PY_SSIZE_T_MAX - digitval) / 10) {[](#l4.27) PyErr_Format(PyExc_ValueError,[](#l4.28) "Too many decimal digits in format string");[](#l4.29) return -1;[](#l4.30) }[](#l4.31)
accumulator += digitval;[](#l4.32)
--- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9648,7 +9648,7 @@ PyObject *PyUnicode_Format(PyObject *for c = *fmt++; if (c < '0' || c > '9') break;
if ((width*10) / 10 != width) {[](#l5.7)
if (width > (PY_SSIZE_T_MAX - ((int)c - '0')) / 10) {[](#l5.8) PyErr_SetString(PyExc_ValueError,[](#l5.9) "width too big");[](#l5.10) goto onError;[](#l5.11)
@@ -9683,7 +9683,7 @@ PyObject *PyUnicode_Format(PyObject *for c = *fmt++; if (c < '0' || c > '9') break;
if ((prec*10) / 10 != prec) {[](#l5.16)
if (prec > (INT_MAX - ((int)c - '0')) / 10) {[](#l5.17) PyErr_SetString(PyExc_ValueError,[](#l5.18) "prec too big");[](#l5.19) goto onError;[](#l5.20)