This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
PATCH: 27_io/istream_extractor_arith.cc (take 2 or 3)
- From: Loren James Rittle <rittle at latour dot rsch dot comm dot mot dot com>
- To: libstdc++ at gcc dot gnu dot org
- Cc: dave dot anglin at nrc dot ca
- Date: Tue, 5 Feb 2002 18:16:59 -0600 (CST)
- Subject: PATCH: 27_io/istream_extractor_arith.cc (take 2 or 3)
- Reply-to: rittle at labs dot mot dot com
>>> test case. It is still failing, at least HP and FreeBSD, due to
>>> undetected overflow on double to float cast in a non-C99 code path.
>> Huh. Bummer. Is there a way to fix this up?
> Yes and no. There is no obvious fix portable to all failing machines.
This version should be even more portable. Fixes
27_io/istream_extractor_arith.cc on alphaev67-dec-osf5.1 and
i386-unknown-freebsd4.4. Still cores inside sscanf() whenever first
argument is over 1024 characters on sparc-sun-solaris2.7 but there is
little we can do about that (except observe yet another reason to
rewrite all these input routines from scratch).
First of all, we try harder to use strtof() or strtold() when
available even if all the machinery of C99 was not available
(alphaev67-dec-osf5.1 and hopefully modern HP-UX). If we still have
to use the other code path, then we try harder to catch error
conditions related to casting strtod() result to float and similar
tightening in the case of handling a long double (helps Solaris 2.7
and FreeBSD).
This code could be further improved once we have a generic portable
way to test for infinity, etc. I am still looking at how I can
improve errno handling in this file per Nathan's points.
David, does this fix HP-UX for you? If not, willing to hack on it
further after I commit it?
* acinclude.m4: Add C++ linkage check for strtof.
* aclocal.m4: Rebuilt.
* config.h.in: Rebuilt.
* configure: Rebuilt.
* config/locale/c_locale_generic.cc: Conditionally include
<ieeefp.h>. Improve handling and error checking of float
and long double input for non-C99 configurations.
Index: acinclude.m4
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/acinclude.m4,v
retrieving revision 1.189
diff -c -r1.189 acinclude.m4
*** acinclude.m4 2002/01/24 20:46:23 1.189
--- acinclude.m4 2002/02/05 23:39:27
***************
*** 661,666 ****
--- 661,667 ----
CXXFLAGS='-fno-builtins -D_GNU_SOURCE'
GLIBCPP_CHECK_STDLIB_DECL_AND_LINKAGE_2(strtold)
+ GLIBCPP_CHECK_STDLIB_DECL_AND_LINKAGE_2(strtof)
AC_CHECK_FUNCS(drand48)
CXXFLAGS="$ac_save_CXXFLAGS"
Index: config/locale/c_locale_generic.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/config/locale/c_locale_generic.cc,v
retrieving revision 1.7
diff -c -r1.7 c_locale_generic.cc
*** c_locale_generic.cc 2002/01/31 00:47:05 1.7
--- c_locale_generic.cc 2002/01/31 23:01:10
***************
*** 35,40 ****
--- 35,44 ----
#include <locale>
+ #ifdef _GLIBCPP_HAVE_IEEEFP_H
+ #include <ieeefp.h>
+ #endif
+
namespace std
{
// Specializations for all types used in num_get.
***************
*** 119,129 ****
const char* __old = setlocale(LC_ALL, "C");
char* __sanity;
errno = 0;
! #ifdef _GLIBCPP_USE_C99
float __f = strtof(__s, &__sanity);
#else
! float __f = static_cast<float>(strtod(__s, &__sanity));
#endif
if (__sanity != __s && *__sanity == '\0' && errno != ERANGE)
__v = __f;
else
--- 123,147 ----
const char* __old = setlocale(LC_ALL, "C");
char* __sanity;
errno = 0;
! #if defined(_GLIBCPP_USE_C99) || defined(_GLIBCPP_HAVE_STRTOF)
float __f = strtof(__s, &__sanity);
+ #else
+ double __d = strtod(__s, &__sanity);
+ float __f = static_cast<float>(__d);
+ #ifdef _GLIBCPP_HAVE_FINITEF
+ if (!finitef (__f))
+ errno = ERANGE;
+ #elif defined (_GLIBCPP_HAVE_FINITE)
+ if (!finite (static_cast<double> (__f)))
+ errno = ERANGE;
+ #elif defined (_GLIBCPP_HAVE_ISINF)
+ if (isinf (static_cast<double> (__f)))
+ errno = ERANGE;
#else
! if (fabs(__d) > numeric_limits<float>::max())
! errno = ERANGE;
#endif
+ #endif
if (__sanity != __s && *__sanity == '\0' && errno != ERANGE)
__v = __f;
else
***************
*** 161,167 ****
{
// Assumes __s formatted for "C" locale.
const char* __old = setlocale(LC_ALL, "C");
! #if defined(_GLIBCPP_USE_C99) && !defined(__hpux)
char* __sanity;
errno = 0;
long double __ld = strtold(__s, &__sanity);
--- 179,185 ----
{
// Assumes __s formatted for "C" locale.
const char* __old = setlocale(LC_ALL, "C");
! #if defined(_GLIBCPP_USE_C99) || defined(_GLIBCPP_HAVE_STRTOLD)
char* __sanity;
errno = 0;
long double __ld = strtold(__s, &__sanity);
***************
*** 170,176 ****
--- 188,201 ----
#else
typedef char_traits<char>::int_type int_type;
long double __ld;
+ errno = 0;
int __p = sscanf(__s, "%Lf", &__ld);
+ if (errno == ERANGE)
+ __p = 0;
+ #ifdef _GLIBCPP_HAVE_FINITEL
+ if ((__p == 1) && !finitel (__ld))
+ __p = 0;
+ #endif
if (__p && static_cast<int_type>(__p) != char_traits<char>::eof())
__v = __ld;
#endif