diff options
author | Tim Peters <tim.peters@gmail.com> | 2000-09-23 03:39:17 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2000-09-23 03:39:17 (GMT) |
commit | ef14d73b7af06d94c7ddf4adf27d1ddeb84d651e (patch) | |
tree | f456e340d1b0ff1909d73c98d7a5bd07e2660cb3 /Objects/floatobject.c | |
parent | 891150bdf2773b9e8ad9e92db073805afd7722cd (diff) | |
download | cpython-ef14d73b7af06d94c7ddf4adf27d1ddeb84d651e.zip cpython-ef14d73b7af06d94c7ddf4adf27d1ddeb84d651e.tar.gz cpython-ef14d73b7af06d94c7ddf4adf27d1ddeb84d651e.tar.bz2 |
Fix for SF bug 110624: float literals behave inconsistently.
I fixed the specific complaint but left the (many) large issues untouched.
See the (very long) bug report discussion for why:
http://sourceforge.net/bugs/?func=detailbug&group_id=5470&bug_id=110624
Note that while I left the interface to the undocumented public API function
PyFloat_FromString alone, its 2nd argument is useless. From a comment block
in the code:
RED_FLAG 22-Sep-2000 tim
PyFloat_FromString's pend argument is braindead. Prior to this RED_FLAG,
1. If v was a regular string, *pend was set to point to its terminating
null byte. That's useless (the caller can find that without any
help from this function!).
2. If v was a Unicode string, or an object convertible to a character
buffer, *pend was set to point into stack trash (the auto temp
vector holding the character buffer). That was downright dangerous.
Since we can't change the interface of a public API function, pend is
still supported but now *officially* useless: if pend is not NULL,
*pend is set to NULL.
Diffstat (limited to 'Objects/floatobject.c')
-rw-r--r-- | Objects/floatobject.c | 60 |
1 files changed, 44 insertions, 16 deletions
diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 774996f..168cbcd 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -117,16 +117,33 @@ PyFloat_FromDouble(double fval) return (PyObject *) op; } +/************************************************************************** +RED_FLAG 22-Sep-2000 tim +PyFloat_FromString's pend argument is braindead. Prior to this RED_FLAG, + +1. If v was a regular string, *pend was set to point to its terminating + null byte. That's useless (the caller can find that without any + help from this function!). + +2. If v was a Unicode string, or an object convertible to a character + buffer, *pend was set to point into stack trash (the auto temp + vector holding the character buffer). That was downright dangerous. + +Since we can't change the interface of a public API function, pend is +still supported but now *officially* useless: if pend is not NULL, +*pend is set to NULL. +**************************************************************************/ PyObject * PyFloat_FromString(PyObject *v, char **pend) { - extern double strtod(const char *, char **); const char *s, *last, *end; double x; - char buffer[256]; /* For errors */ - char s_buffer[256]; + char buffer[256]; /* for errors */ + char s_buffer[256]; /* for objects convertible to a char buffer */ int len; + if (pend) + *pend = NULL; if (PyString_Check(v)) { s = PyString_AS_STRING(v); len = PyString_GET_SIZE(v); @@ -134,10 +151,10 @@ PyFloat_FromString(PyObject *v, char **pend) else if (PyUnicode_Check(v)) { if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) { PyErr_SetString(PyExc_ValueError, - "float() literal too large to convert"); + "Unicode float() literal too long to convert"); return NULL; } - if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), + if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), PyUnicode_GET_SIZE(v), s_buffer, NULL)) @@ -154,18 +171,30 @@ PyFloat_FromString(PyObject *v, char **pend) last = s + len; while (*s && isspace(Py_CHARMASK(*s))) s++; - if (s[0] == '\0') { + if (*s == '\0') { PyErr_SetString(PyExc_ValueError, "empty string for float()"); return NULL; } + /* We don't care about overflow or underflow. If the platform supports + * them, infinities and signed zeroes (on underflow) are fine. + * However, strtod can return 0 for denormalized numbers, where atof + * does not. So (alas!) we special-case a zero result. Note that + * whether strtod sets errno on underflow is not defined, so we can't + * key off errno. + */ + x = strtod(s, (char **)&end); errno = 0; - PyFPE_START_PROTECT("PyFloat_FromString", return 0) - x = strtod((char *)s, (char **)&end); - PyFPE_END_PROTECT(x) /* Believe it or not, Solaris 2.6 can move end *beyond* the null - byte at the end of the string, when the input is inf(inity) */ + byte at the end of the string, when the input is inf(inity). */ if (end > last) end = last; + if (end == s) { + sprintf(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 (*end && isspace(Py_CHARMASK(*end))) end++; if (*end != '\0') { @@ -178,13 +207,12 @@ PyFloat_FromString(PyObject *v, char **pend) "null byte in argument for float()"); return NULL; } - else if (errno != 0) { - sprintf(buffer, "float() literal too large: %.200s", s); - PyErr_SetString(PyExc_ValueError, buffer); - return NULL; + if (x == 0.0) { + /* See above -- may have been strtod being anal + about denorms. */ + x = atof(s); + errno = 0; /* whether atof ever set errno is undefined */ } - if (pend) - *pend = (char *)end; return PyFloat_FromDouble(x); } |