Issue #7117: Use PyOS_string_to_double instead of PyOS_ascii_strtod in

floatobject.c.  Also, remove limitation on length of unicode inputs to
float().
This commit is contained in:
Mark Dickinson 2009-10-26 21:11:20 +00:00
parent 3e1eb0f715
commit 8568b19850
2 changed files with 24 additions and 37 deletions

View File

@ -31,8 +31,6 @@ class GeneralFloatCases(unittest.TestCase):
if test_support.have_unicode: if test_support.have_unicode:
self.assertEqual(float(unicode(" 3.14 ")), 3.14) self.assertEqual(float(unicode(" 3.14 ")), 3.14)
self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14) self.assertEqual(float(unicode(" \u0663.\u0661\u0664 ",'raw-unicode-escape')), 3.14)
# Implementation limitation in PyFloat_FromString()
self.assertRaises(ValueError, float, unicode("1"*10000))
@test_support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE') @test_support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
def test_float_with_comma(self): def test_float_with_comma(self):

View File

@ -181,9 +181,10 @@ PyFloat_FromString(PyObject *v, char **pend)
double x; double x;
char buffer[256]; /* for errors */ char buffer[256]; /* for errors */
#ifdef Py_USING_UNICODE #ifdef Py_USING_UNICODE
char s_buffer[256]; /* for objects convertible to a char buffer */ char *s_buffer = NULL;
#endif #endif
Py_ssize_t len; Py_ssize_t len;
PyObject *result = NULL;
if (pend) if (pend)
*pend = NULL; *pend = NULL;
@ -193,23 +194,21 @@ PyFloat_FromString(PyObject *v, char **pend)
} }
#ifdef Py_USING_UNICODE #ifdef Py_USING_UNICODE
else if (PyUnicode_Check(v)) { else if (PyUnicode_Check(v)) {
if (PyUnicode_GET_SIZE(v) >= (Py_ssize_t)sizeof(s_buffer)) { s_buffer = (char *)PyMem_MALLOC(PyUnicode_GET_SIZE(v)+1);
PyErr_SetString(PyExc_ValueError, if (s_buffer == NULL)
"Unicode float() literal too long to convert"); return PyErr_NoMemory();
return NULL;
}
if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v),
PyUnicode_GET_SIZE(v), PyUnicode_GET_SIZE(v),
s_buffer, s_buffer,
NULL)) NULL))
return NULL; goto error;
s = s_buffer; s = s_buffer;
len = strlen(s); len = strlen(s);
} }
#endif #endif
else if (PyObject_AsCharBuffer(v, &s, &len)) { else if (PyObject_AsCharBuffer(v, &s, &len)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"float() argument must be a string or a number"); "float() argument must be a string or a number");
return NULL; return NULL;
} }
last = s + len; last = s + len;
@ -219,36 +218,26 @@ PyFloat_FromString(PyObject *v, char **pend)
/* We don't care about overflow or underflow. If the platform /* We don't care about overflow or underflow. If the platform
* supports them, infinities and signed zeroes (on underflow) are * supports them, infinities and signed zeroes (on underflow) are
* fine. */ * fine. */
errno = 0; x = PyOS_string_to_double(s, (char **)&end, NULL);
PyFPE_START_PROTECT("strtod", return NULL) if (x == -1.0 && PyErr_Occurred())
x = PyOS_ascii_strtod(s, (char **)&end); goto error;
PyFPE_END_PROTECT(x)
if (end == s) {
if (errno == ENOMEM)
PyErr_NoMemory();
else {
PyOS_snprintf(buffer, sizeof(buffer),
"invalid literal for float(): %.200s", s);
PyErr_SetString(PyExc_ValueError, buffer);
}
return NULL;
}
/* Since end != s, the platform made *some* kind of sense out
of the input. Trust it. */
while (Py_ISSPACE(*end)) while (Py_ISSPACE(*end))
end++; end++;
if (end != last) { if (end == last)
if (*end == '\0') result = PyFloat_FromDouble(x);
PyErr_SetString(PyExc_ValueError, else {
"null byte in argument for float()"); PyOS_snprintf(buffer, sizeof(buffer),
else { "invalid literal for float(): %.200s", s);
PyOS_snprintf(buffer, sizeof(buffer), PyErr_SetString(PyExc_ValueError, buffer);
"invalid literal for float(): %.200s", s); result = NULL;
PyErr_SetString(PyExc_ValueError, buffer);
}
return NULL;
} }
return PyFloat_FromDouble(x);
error:
#ifdef Py_USING_UNICODE
if (s_buffer)
PyMem_FREE(s_buffer);
#endif
return result;
} }
static void static void