diff options
-rw-r--r-- | Lib/test/string_tests.py | 9 | ||||
-rw-r--r-- | Misc/NEWS | 4 | ||||
-rw-r--r-- | Objects/stringobject.c | 78 | ||||
-rw-r--r-- | Objects/unicodeobject.c | 78 |
4 files changed, 47 insertions, 122 deletions
diff --git a/Lib/test/string_tests.py b/Lib/test/string_tests.py index e66855d..caff3d4 100644 --- a/Lib/test/string_tests.py +++ b/Lib/test/string_tests.py @@ -1090,14 +1090,7 @@ class MixinStrUnicodeUserStringTest: value = 0.01 for x in xrange(60): value = value * 3.141592655 / 3.0 * 10.0 - # 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 and prec >= 67: - self.checkraises(OverflowError, format, "__mod__", value) - else: - self.checkcall(format, "__mod__", value) + self.checkcall(format, "__mod__", value) def test_inplace_rewrites(self): # Check that strings don't copy and modify cached single-character strings @@ -12,6 +12,10 @@ What's New in Python 2.7 alpha 1 Core and Builtins ----------------- +- Remove restrictions on precision when formatting floats. E.g., + "%.120g" % 1e-100 used to raise OverflowError, but now gives the + requested 120 significant digits instead. + - Add Py3k warnings for parameter names in parenthesis. - Issue #7362: Give a proper error message for def f((x)=3): pass. diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 4746b3c..1d9ba8c 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -4379,72 +4379,36 @@ getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) #define F_ALT (1<<3) #define F_ZERO (1<<4) -Py_LOCAL_INLINE(int) -formatfloat(char *buf, size_t buflen, int flags, - int prec, int type, PyObject *v) +/* Returns a new reference to a PyString object, or NULL on failure. */ + +static PyObject * +formatfloat(PyObject *v, int flags, int prec, int type) { - char *tmp; + char *p; + PyObject *result; double x; - Py_ssize_t len; x = PyFloat_AsDouble(v); if (x == -1.0 && PyErr_Occurred()) { PyErr_Format(PyExc_TypeError, "float argument required, " "not %.200s", Py_TYPE(v)->tp_name); - return -1; + return NULL; } + if (prec < 0) prec = 6; -#if SIZEOF_INT > 4 - /* make sure that the decimal representation of precision really does - need at most 10 digits: platforms with sizeof(int) == 8 exist! */ - if (prec > 0x7fffffff) { - PyErr_SetString(PyExc_OverflowError, - "outrageously large precision " - "for formatted float"); - return -1; - } -#endif if (type == 'f' && fabs(x) >= 1e50) type = 'g'; - /* 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 + p = PyOS_double_to_string(x, type, prec, + (flags & F_ALT) ? Py_DTSF_ALT : 0, NULL); - '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 the length by one. - - */ - if (((type == 'g' || 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; - } - tmp = PyOS_double_to_string(x, type, prec, - (flags&F_ALT)?Py_DTSF_ALT:0, NULL); - if (!tmp) - return -1; - len = strlen(tmp); - if (len >= buflen) { - PyErr_SetString(PyExc_OverflowError, - "formatted float is too long (precision too large?)"); - PyMem_Free(tmp); - return -1; - } - strcpy(buf, tmp); - PyMem_Free(tmp); - return (int)len; + if (p == NULL) + return NULL; + result = PyString_FromStringAndSize(p, strlen(p)); + PyMem_Free(p); + return result; } /* _PyString_FormatLong emulates the format codes d, u, o, x and X, and @@ -4684,7 +4648,7 @@ formatchar(char *buf, size_t buflen, PyObject *v) /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) - FORMATBUFLEN is the length of the buffer in which the floats, ints, & + FORMATBUFLEN is the length of the buffer in which the ints & chars are formatted. XXX This is a magic number. Each formatting routine does bounds checking to ensure no overflow, but a better solution may be to malloc a buffer of appropriate size for each @@ -4754,7 +4718,7 @@ PyString_Format(PyObject *format, PyObject *args) int sign; Py_ssize_t len; char formatbuf[FORMATBUFLEN]; - /* For format{float,int,char}() */ + /* For format{int,char}() */ #ifdef Py_USING_UNICODE char *fmt_start = fmt; Py_ssize_t argidx_start = argidx; @@ -5007,11 +4971,11 @@ PyString_Format(PyObject *format, PyObject *args) case 'G': if (c == 'F') c = 'f'; - pbuf = formatbuf; - len = formatfloat(pbuf, sizeof(formatbuf), - flags, prec, c, v); - if (len < 0) + temp = formatfloat(v, flags, prec, c); + if (temp == NULL) goto error; + pbuf = PyString_AS_STRING(temp); + len = PyString_GET_SIZE(temp); sign = 1; if (flags & F_ZERO) fill = '0'; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 65c10b1..401f7be 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -8302,68 +8302,32 @@ longtounicode(Py_UNICODE *buffer, size_t len, const char *format, long x) shared with stringobject.c, converting from 8-bit to Unicode after the formatting is done. */ -static int -formatfloat(Py_UNICODE *buf, - size_t buflen, - int flags, - int prec, - int type, - PyObject *v) +/* Returns a new reference to a PyUnicode object, or NULL on failure. */ + +static PyObject * +formatfloat(PyObject *v, int flags, int prec, int type) { + char *p; + PyObject *result; double x; - Py_ssize_t result; - char *tmp; x = PyFloat_AsDouble(v); if (x == -1.0 && PyErr_Occurred()) - return -1; + return NULL; + if (prec < 0) prec = 6; -#if SIZEOF_INT > 4 - /* make sure that the decimal representation of precision really does - need at most 10 digits: platforms with sizeof(int) == 8 exist! */ - if (prec > 0x7fffffff) { - PyErr_SetString(PyExc_OverflowError, - "outrageously large precision " - "for formatted float"); - return -1; - } -#endif if (type == 'f' && fabs(x) >= 1e50) type = 'g'; - /* 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 the length by one. - - */ - if (((type == 'g' || 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; - } - - tmp = PyOS_double_to_string(x, type, prec, - (flags&F_ALT)?Py_DTSF_ALT:0, NULL); - if (!tmp) - return -1; - - result = strtounicode(buf, tmp); - PyMem_Free(tmp); - return Py_SAFE_DOWNCAST(result, Py_ssize_t, int); + p = PyOS_double_to_string(x, type, prec, + (flags & F_ALT) ? Py_DTSF_ALT : 0, NULL); + if (p == NULL) + return NULL; + result = PyUnicode_FromStringAndSize(p, strlen(p)); + PyMem_Free(p); + return result; } static PyObject* @@ -8516,7 +8480,7 @@ formatchar(Py_UNICODE *buf, /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) - FORMATBUFLEN is the length of the buffer in which the floats, ints, & + FORMATBUFLEN is the length of the buffer in which the ints & chars are formatted. XXX This is a magic number. Each formatting routine does bounds checking to ensure no overflow, but a better solution may be to malloc a buffer of appropriate size for each @@ -8587,7 +8551,7 @@ PyObject *PyUnicode_Format(PyObject *format, Py_UNICODE *pbuf; Py_UNICODE sign; Py_ssize_t len; - Py_UNICODE formatbuf[FORMATBUFLEN]; /* For format{float,int,char}() */ + Py_UNICODE formatbuf[FORMATBUFLEN]; /* For format{int,char}() */ fmt++; if (*fmt == '(') { @@ -8850,11 +8814,11 @@ PyObject *PyUnicode_Format(PyObject *format, case 'G': if (c == 'F') c = 'f'; - pbuf = formatbuf; - len = formatfloat(pbuf, sizeof(formatbuf)/sizeof(Py_UNICODE), - flags, prec, c, v); - if (len < 0) + temp = formatfloat(v, flags, prec, c); + if (temp == NULL) goto onError; + pbuf = PyUnicode_AS_UNICODE(temp); + len = PyUnicode_GET_SIZE(temp); sign = 1; if (flags & F_ZERO) fill = '0'; |