[Python-checkins] CVS: python/dist/src/Objects floatobject.c,2.70,2.71

Tim Peters python-dev@python.org
Fri, 22 Sep 2000 20:39:20 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory slayer.i.sourceforge.net:/tmp/cvs-serv9812/python/dist/src/objects

Modified Files:
	floatobject.c 
Log Message:
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.


Index: floatobject.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/floatobject.c,v
retrieving revision 2.70
retrieving revision 2.71
diff -C2 -r2.70 -r2.71
*** floatobject.c	2000/09/16 03:54:24	2.70
--- floatobject.c	2000/09/23 03:39:17	2.71
***************
*** 118,131 ****
  }
  
  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];
  	int len;
  
  	if (PyString_Check(v)) {
  		s = PyString_AS_STRING(v);
--- 118,148 ----
  }
  
+ /**************************************************************************
+ 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)
  {
  	const char *s, *last, *end;
  	double x;
! 	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);
***************
*** 135,142 ****
  		if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) {
  			PyErr_SetString(PyExc_ValueError,
! 				 "float() literal too large to convert");
  			return NULL;
  		}
! 		if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), 
  					    PyUnicode_GET_SIZE(v),
  					    s_buffer, 
--- 152,159 ----
  		if (PyUnicode_GET_SIZE(v) >= sizeof(s_buffer)) {
  			PyErr_SetString(PyExc_ValueError,
! 				"Unicode float() literal too long to convert");
  			return NULL;
  		}
! 		if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v),
  					    PyUnicode_GET_SIZE(v),
  					    s_buffer, 
***************
*** 155,170 ****
  	while (*s && isspace(Py_CHARMASK(*s)))
  		s++;
! 	if (s[0] == '\0') {
  		PyErr_SetString(PyExc_ValueError, "empty string for float()");
  		return NULL;
  	}
  	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) */
  	if (end > last)
  		end = last;
  	while (*end && isspace(Py_CHARMASK(*end)))
  		end++;
--- 172,199 ----
  	while (*s && isspace(Py_CHARMASK(*s)))
  		s++;
! 	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;
  	/* 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). */
  	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++;
***************
*** 179,189 ****
  		return NULL;
  	}
! 	else if (errno != 0) {
! 		sprintf(buffer, "float() literal too large: %.200s", s);
! 		PyErr_SetString(PyExc_ValueError, buffer);
! 		return NULL;
  	}
- 	if (pend)
- 		*pend = (char *)end;
  	return PyFloat_FromDouble(x);
  }
--- 208,217 ----
  		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 */
  	}
  	return PyFloat_FromDouble(x);
  }