[multiple changes]
authorBenjamin Kosnik <bkoz@gcc.gnu.org>
Fri, 7 Dec 2001 02:58:36 +0000 (02:58 +0000)
committerBenjamin Kosnik <bkoz@gcc.gnu.org>
Fri, 7 Dec 2001 02:58:36 +0000 (02:58 +0000)
2001-12-06  Benjamin Kosnik  <bkoz@redhat.com>

libstdc++/3720
* include/bits/locale_facets.tcc (num_put): Clean.
(num_get::_M_extract_float): Change argument to string.
(num_get::do_get(float)): Fixup.
(num_get::do_get(double)): Same.
(num_get::do_get(long double)): Same.
(num_get::_M_extract_int): Add maximum length parameter, __max.
(num_get::_M_extract_float): Correct zeros, use string.
* include/bits/locale_facets.h (num_get::_M_extract_float): Change
declaration here.
* src/locale.cc (__num_base::_S_atoms): Remove x, X.
* testsuite/27_io/istream_extractor_arith.cc (test13): Add.

2001-12-06  Philip Martin  <pmartin@uklinux.net>

* testsuite/27_io/istream_extractor_arith.cc (test12): Add
tests for excess input digits.

From-SVN: r47743

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/locale_facets.h
libstdc++-v3/include/bits/locale_facets.tcc
libstdc++-v3/src/locale.cc
libstdc++-v3/testsuite/27_io/istream_extractor_arith.cc

index b5dfa19c71e3d932da19b907b4edebef63939cfb..4348d33f44de79f43dd5379de196943df00454db 100644 (file)
@@ -1,3 +1,23 @@
+2001-12-06  Benjamin Kosnik  <bkoz@redhat.com>
+
+       libstdc++/3720
+       * include/bits/locale_facets.tcc (num_put): Clean.
+       (num_get::_M_extract_float): Change argument to string. 
+       (num_get::do_get(float)): Fixup.
+       (num_get::do_get(double)): Same.
+       (num_get::do_get(long double)): Same.
+       (num_get::_M_extract_int): Add maximum length parameter, __max.
+       (num_get::_M_extract_float): Correct zeros, use string.
+       * include/bits/locale_facets.h (num_get::_M_extract_float): Change
+       declaration here.
+       * src/locale.cc (__num_base::_S_atoms): Remove x, X.
+       * testsuite/27_io/istream_extractor_arith.cc (test13): Add.
+       
+2001-12-06  Philip Martin  <pmartin@uklinux.net>
+
+       * testsuite/27_io/istream_extractor_arith.cc (test12): Add
+       tests for excess input digits.
+
 2001-12-06  Phil Edwards  <pme@gcc.gnu.org>
 
        * include/bits/std_bitset.h:  Use GLIBCPP in multiple-inclusion guard.
@@ -42,7 +62,7 @@
 2001-12-04  Paolo Carlini <pcarlini@unitus.it>
 
         libstdc++/4402
-        * testsuite/27_io/ostream_inserter_arith.cc (test02): add testcase
+        * testsuite/27_io/ostream_inserter_arith.cc (test02): Add testcase
        from the PR.
         * include/bits/locale_facets.tcc (num_put::_M_convert_float):
         Deal properly with long ios_base::fixed floats.
index 878f8b28cabc68a8d2796374e8bb84c5739c037c..27bd5b15ac7ac48723389f79689bf335e65c083e 100644 (file)
@@ -420,7 +420,7 @@ namespace std
   {
   public:
     // String literal of acceptable (narrow) input, for num_get.
-    // "0123456789eEabcdfxABCDFX"
+    // "0123456789eEabcdfABCDF"
     static const char _S_atoms[];
 
     enum 
@@ -428,7 +428,7 @@ namespace std
       _M_zero,
       _M_e = _M_zero + 10,
       _M_E = _M_zero + 11,
-      _M_size = 23 + 1
+      _M_size = 21 + 1
     };
 
     // Construct and return valid scanf format for floating point types.
@@ -634,11 +634,11 @@ namespace std
 
       void 
       _M_extract_float(iter_type, iter_type, ios_base&, ios_base::iostate&, 
-                      char* __xtrc) const;
+                      string& __xtrc) const;
 
       void 
       _M_extract_int(iter_type, iter_type, ios_base&, ios_base::iostate&, 
-                    char* __xtrc, int& __base) const;
+                    char* __xtrc, int __max, int& __base) const;
 
       virtual iter_type 
       do_get(iter_type, iter_type, ios_base&, ios_base::iostate&, bool&) const;
index 95cbee5d8f14446ffe8e6764663bdabb8e2b73d7..363ff8b54a0281d5b3d66d2a5a5bd2eff78bd4cb 100644 (file)
@@ -35,6 +35,7 @@
 #include <bits/std_cerrno.h>
 #include <bits/std_clocale.h>   // For localeconv
 #include <bits/std_cstdlib.h>   // For strof, strtold
+#include <bits/std_cmath.h>   // For ceil
 #include <bits/std_limits.h>    // For numeric_limits
 #include <bits/std_memory.h>    // For auto_ptr
 #include <bits/streambuf_iterator.h>     // For streambuf_iterators
@@ -90,20 +91,21 @@ namespace std
     void
     num_get<_CharT, _InIter>::
     _M_extract_float(_InIter __beg, _InIter __end, ios_base& __io,
-                    ios_base::iostate& __err, char* __xtrc) const
+                    ios_base::iostate& __err, string& __xtrc) const
     {
       const locale __loc = __io.getloc();
       const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
       const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc);
-      int __pos = 0;
-      char_type  __c = *__beg;
 
       // Check first for sign.
       const char_type __plus = __ctype.widen('+');
       const char_type __minus = __ctype.widen('-');
+      int __pos = 0;
+      char_type  __c = *__beg;
       if ((__c == __plus || __c == __minus) && __beg != __end)
        {
-         __xtrc[__pos++] = __ctype.narrow(__c, char());
+         __xtrc += __ctype.narrow(__c, char());
+         ++__pos;
          __c = *(++__beg);
        }
 
@@ -116,7 +118,10 @@ namespace std
          __found_zero = true;
        }
       if (__found_zero)
-       __xtrc[__pos++] = _S_atoms[_M_zero];
+       {
+         __xtrc += _S_atoms[_M_zero];
+         ++__pos;
+       }
 
       // Only need acceptable digits for floating point numbers.
       const size_t __len = _M_E - _M_zero + 1;
@@ -142,7 +147,8 @@ namespace std
           if (__p && __c)
            {
              // Try first for acceptable digit; record it if found.
-             __xtrc[__pos++] = _S_atoms[__p - __watoms];
+             ++__pos;
+             __xtrc += _S_atoms[__p - __watoms];
              ++__sep_pos;
              __c = *(++__beg);
            }
@@ -165,7 +171,8 @@ namespace std
          else if (__c == __dec && !__found_dec)
            {
              __found_grouping += static_cast<char>(__sep_pos);
-             __xtrc[__pos++] = '.';
+             ++__pos;
+             __xtrc += '.';
              __c = *(++__beg);
              __found_dec = true;
            }
@@ -173,13 +180,15 @@ namespace std
                   && !__found_sci && __pos)
            {
              // Scientific notation.
-             __xtrc[__pos++] = __ctype.narrow(__c, char());
+             ++__pos;
+             __xtrc += __ctype.narrow(__c, char());
              __c = *(++__beg);
 
              // Remove optional plus or minus sign, if they exist.
              if (__c == __plus || __c == __minus)
                {
-                 __xtrc[__pos++] = __ctype.narrow(__c, char());
+                 ++__pos;
+                 __xtrc += __ctype.narrow(__c, char());
                  __c = *(++__beg);
                }
              __found_sci = true;
@@ -196,19 +205,12 @@ namespace std
           // Add the ending grouping if a decimal wasn't found.
          if (!__found_dec)
            __found_grouping += static_cast<char>(__sep_pos);
-
           if (!__verify_grouping(__grouping, __found_grouping))
-            {
-              __err |= ios_base::failbit;
-              __xtrc[__pos] = '\0';
-              if (__beg == __end)
-                __err |= ios_base::eofbit;
-              return;
-            }
+           __err |= ios_base::failbit;
         }
 
       // Finish up
-      __xtrc[__pos] = char_type();
+      __xtrc += char();
       if (__beg == __end)
         __err |= ios_base::eofbit;
     }
@@ -217,9 +219,15 @@ namespace std
     void
     num_get<_CharT, _InIter>::
     _M_extract_int(_InIter __beg, _InIter __end, ios_base& __io,
-                  ios_base::iostate& __err, char* __xtrc, int& __base) const
+                  ios_base::iostate& __err, char* __xtrc, int __max, 
+                  int& __base) const
     {
+      const locale __loc = __io.getloc();
+      const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
+      const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc);
       // Stage 1: determine a conversion specifier.
+      // NB: Iff __basefield == 0, this can change based on contents.
       ios_base::fmtflags __basefield = __io.flags() & ios_base::basefield;
       if (__basefield == ios_base::oct)
         __base = 8;
@@ -228,13 +236,9 @@ namespace std
       else
        __base = 10;
 
-      const locale __loc = __io.getloc();
-      const ctype<_CharT>& __ctype = use_facet<ctype<_CharT> >(__loc);
-      const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__loc);
+     // Check first for sign.
       int __pos = 0;
       char_type  __c = *__beg;
-
-      // Check first for sign.
       if ((__c == __ctype.widen('+') || __c == __ctype.widen('-'))
          && __beg != __end)
        {
@@ -242,24 +246,45 @@ namespace std
          __c = *(++__beg);
        }
 
-      // Next, strip leading zeros
+      // Next, strip leading zeros and check required digits for base formats.
       const char_type __zero = __ctype.widen(_S_atoms[_M_zero]);
-      bool __found_zero = false;
-      while (__base == 10 && __c == __zero && __beg != __end)
+      const char_type __x = __ctype.widen('x');
+      const char_type __X = __ctype.widen('X');
+      if (__base == 10)
        {
-         __c = *(++__beg);
-         __found_zero = true;
+         bool __found_zero = false;
+         while (__c == __zero && __beg != __end)
+           {
+             __c = *(++__beg);
+             __found_zero = true;
+           }
+         if (__found_zero)
+           {
+             __xtrc[__pos++] = _S_atoms[_M_zero];
+             if (__basefield == 0)
+               {             
+                 if ((__c == __x || __c == __X) && __beg != __end)
+                   {
+                     __xtrc[__pos++] = __ctype.narrow(__c, char());
+                     __c = *(++__beg);
+                     __base = 16;
+                   }
+                 else 
+                   __base = 8;
+               }
+           }
        }
-      if (__found_zero)
+      else if (__base == 16)
        {
-         __xtrc[__pos++] = _S_atoms[_M_zero];
-         if (__basefield == 0)
+         if (__c == __zero && __beg != __end)
            {
-             // Depending on what is discovered, the base may change.
-             if (__c == __ctype.widen('x') || __c == __ctype.widen('X'))
-               __base = 16;
-             else
-               __base = 8;
+             __xtrc[__pos++] = _S_atoms[_M_zero];
+             __c = *(++__beg); 
+             if  ((__c == __x || __c == __X) && __beg != __end)
+               {
+                 __xtrc[__pos++] = __ctype.narrow(__c, char());
+                 __c = *(++__beg);
+               }
            }
        }
 
@@ -271,14 +296,26 @@ namespace std
       else
        __len = __base;
 
-      char_type  __watoms[_M_size];
+      // Figure out the maximum number of digits that can be extracted
+      // for the given type, using the determined base.
+      int __max_digits;
+      if (__base != 10)
+       __max_digits = static_cast<int>(ceil(__max * log(10.0)
+                                          /log(static_cast<double>(__base))));
+      else 
+       __max_digits = __max;
+      // Add in what's already been extracted.
+      __max_digits += __pos;
+
+      // Extract.
+      char_type __watoms[_M_size];
       __ctype.widen(_S_atoms, _S_atoms + __len, __watoms);
       string __found_grouping;
       const string __grouping = __np.grouping();
       bool __check_grouping = __grouping.size() && __base == 10;
       int __sep_pos = 0;
       const char_type __sep = __np.thousands_sep();
-      while (__beg != __end)
+      while (__beg != __end && __pos <= __max_digits)
         {
          typedef char_traits<_CharT>   __traits_type;
           const char_type* __p = __traits_type::find(__watoms, __len,  __c);
@@ -312,25 +349,22 @@ namespace std
            break;
         }
 
+      // If one more than the maximum number of digits is extracted.
+      if (__pos > __max_digits)
+       __err |= ios_base::failbit;
+
       // Digit grouping is checked. If grouping and found_grouping don't
       // match, then get very very upset, and set failbit.
       if (__check_grouping && __found_grouping.size())
         {
-          // Add the ending grouping
+          // Add the ending grouping.
           __found_grouping += static_cast<char>(__sep_pos);
-
           if (!__verify_grouping(__grouping, __found_grouping))
-            {
-              __err |= ios_base::failbit;
-              __xtrc[__pos] = '\0';
-              if (__beg == __end)
-                __err |= ios_base::eofbit;
-              return;
-            }
+           __err |= ios_base::failbit;
         }
 
       // Finish up
-      __xtrc[__pos] = char_type();
+      __xtrc[__pos] = char();
       if (__beg == __end)
         __err |= ios_base::eofbit;
     }
@@ -351,10 +385,11 @@ namespace std
 
           // Stage 1: extract and determine the conversion specifier.
           // Assuming leading zeros eliminated, thus the size of 32 for
-          // integral types.
-          char __xtrc[32] = {'\0'};
+          // integral types
+          char __xtrc[32];
           int __base;
-          _M_extract_int(__beg, __end, __io, __err, __xtrc, __base);
+          _M_extract_int(__beg, __end, __io, __err, __xtrc, 
+                        numeric_limits<bool>::digits10, __base);
 
           // Stage 2: convert and store results.
           char* __sanity;
@@ -416,9 +451,10 @@ namespace std
       // Stage 1: extract and determine the conversion specifier.
       // Assuming leading zeros eliminated, thus the size of 32 for
       // integral types.
-      char __xtrc[32]= {'\0'};
+      char __xtrc[32];
       int __base;
-      _M_extract_int(__beg, __end, __io, __err, __xtrc, __base);
+      _M_extract_int(__beg, __end, __io, __err, __xtrc, 
+                    numeric_limits<long>::digits10, __base);
 
       // Stage 2: convert and store results.
       char* __sanity;
@@ -441,9 +477,10 @@ namespace std
       // Stage 1: extract and determine the conversion specifier.
       // Assuming leading zeros eliminated, thus the size of 32 for
       // integral types.
-      char __xtrc[32]= {'\0'};
+      char __xtrc[32];
       int __base;
-      _M_extract_int(__beg, __end, __io, __err, __xtrc, __base);
+      _M_extract_int(__beg, __end, __io, __err, __xtrc, 
+                    numeric_limits<unsigned short>::digits10, __base);
 
       // Stage 2: convert and store results.
       char* __sanity;
@@ -467,9 +504,10 @@ namespace std
       // Stage 1: extract and determine the conversion specifier.
       // Assuming leading zeros eliminated, thus the size of 32 for
       // integral types.
-      char __xtrc[32]= {'\0'};
+      char __xtrc[32];
       int __base;
-      _M_extract_int(__beg, __end, __io, __err, __xtrc, __base);
+      _M_extract_int(__beg, __end, __io, __err, __xtrc, 
+                    numeric_limits<unsigned int>::digits10, __base);
 
       // Stage 2: convert and store results.
       char* __sanity;
@@ -493,9 +531,10 @@ namespace std
       // Stage 1: extract and determine the conversion specifier.
       // Assuming leading zeros eliminated, thus the size of 32 for
       // integral types.
-      char __xtrc[32] = {'\0'};
+      char __xtrc[32];
       int __base;
-      _M_extract_int(__beg, __end, __io, __err, __xtrc, __base);
+      _M_extract_int(__beg, __end, __io, __err, __xtrc, 
+                    numeric_limits<unsigned long>::digits10, __base);
 
       // Stage 2: convert and store results.
       char* __sanity;
@@ -519,9 +558,10 @@ namespace std
       // Stage 1: extract and determine the conversion specifier.
       // Assuming leading zeros eliminated, thus the size of 32 for
       // integral types.
-      char __xtrc[32]= {'\0'};
+      char __xtrc[32];
       int __base;
-      _M_extract_int(__beg, __end, __io, __err, __xtrc, __base);
+      _M_extract_int(__beg, __end, __io, __err, __xtrc, 
+                    numeric_limits<long long>::digits10, __base);
 
       // Stage 2: convert and store results.
       char* __sanity;
@@ -544,9 +584,10 @@ namespace std
       // Stage 1: extract and determine the conversion specifier.
       // Assuming leading zeros eliminated, thus the size of 32 for
       // integral types.
-      char __xtrc[32]= {'\0'};
+      char __xtrc[32];
       int __base;
-      _M_extract_int(__beg, __end, __io, __err, __xtrc, __base);
+      _M_extract_int(__beg, __end, __io, __err, __xtrc,
+                    numeric_limits<unsigned long long>::digits10, __base);
 
       // Stage 2: convert and store results.
       char* __sanity;
@@ -568,21 +609,20 @@ namespace std
           ios_base::iostate& __err, float& __v) const
     {
       // Stage 1: extract and determine the conversion specifier.
-      // Assuming leading zeros eliminated, thus the size of 256 for
-      // floating-point types.
-      char __xtrc[32]= {'\0'};
+      string __xtrc;
+      __xtrc.reserve(32);
       _M_extract_float(__beg, __end, __io, __err, __xtrc);
 
       // Stage 2: convert and store results.
       char* __sanity;
       errno = 0;
 #ifdef _GLIBCPP_USE_C99
-      float __f = strtof(__xtrc, &__sanity);
+      float __f = strtof(__xtrc.c_str(), &__sanity);
 #else
-      float __f = static_cast<float>(strtod(__xtrc, &__sanity));
+      float __f = static_cast<float>(strtod(__xtrc.c_str(), &__sanity));
 #endif
       if (!(__err & ios_base::failbit)
-          && __sanity != __xtrc && *__sanity == '\0' && errno == 0)
+          && __sanity != __xtrc.c_str() && *__sanity == '\0' && errno == 0)
         __v = __f;
       else
         __err |= ios_base::failbit;
@@ -596,17 +636,16 @@ namespace std
            ios_base::iostate& __err, double& __v) const
     {
       // Stage 1: extract and determine the conversion specifier.
-      // Assuming leading zeros eliminated, thus the size of 256 for
-      // floating-point types.
-      char __xtrc[32]= {'\0'};
+      string __xtrc;
+      __xtrc.reserve(32);
       _M_extract_float(__beg, __end, __io, __err, __xtrc);
 
       // Stage 2: convert and store results.
       char* __sanity;
       errno = 0;
-      double __d = strtod(__xtrc, &__sanity);
+      double __d = strtod(__xtrc.c_str(), &__sanity);
       if (!(__err & ios_base::failbit)
-          && __sanity != __xtrc && *__sanity == '\0' && errno == 0)
+          && __sanity != __xtrc.c_str() && *__sanity == '\0' && errno == 0)
         __v = __d;
       else
         __err |= ios_base::failbit;
@@ -620,18 +659,17 @@ namespace std
            ios_base::iostate& __err, long double& __v) const
     {
       // Stage 1: extract and determine the conversion specifier.
-      // Assuming leading zeros eliminated, thus the size of 256 for
-      // floating-point types.
-      char __xtrc[32]= {'\0'};
+      string __xtrc;
+      __xtrc.reserve(32);
       _M_extract_float(__beg, __end, __io, __err, __xtrc);
 
 #if defined(_GLIBCPP_USE_C99) && !defined(__hpux)
       // Stage 2: convert and store results.
       char* __sanity;
       errno = 0;
-      long double __ld = strtold(__xtrc, &__sanity);
+      long double __ld = strtold(__xtrc.c_str(), &__sanity);
       if (!(__err & ios_base::failbit)
-          && __sanity != __xtrc && *__sanity == '\0' && errno == 0)
+          && __sanity != __xtrc.c_str() && *__sanity == '\0' && errno == 0)
         __v = __ld;
 #else
       // Stage 2: determine a conversion specifier.
@@ -649,7 +687,7 @@ namespace std
       // Stage 3: store results.
       typedef typename char_traits<_CharT>::int_type int_type;
       long double __ld;
-      int __p = sscanf(__xtrc, __conv, &__ld);
+      int __p = sscanf(__xtrc.c_str(), __conv, &__ld);
       if (!(__err & ios_base::failbit) && __p 
          && static_cast<int_type>(__p) != char_traits<_CharT>::eof())
         __v = __ld;
@@ -675,9 +713,10 @@ namespace std
       // Stage 1: extract and determine the conversion specifier.
       // Assuming leading zeros eliminated, thus the size of 32 for
       // integral types.
-      char __xtrc[32]= {'\0'};
+      char __xtrc[32];
       int __base;
-      _M_extract_int(__beg, __end, __io, __err, __xtrc, __base);
+      _M_extract_int(__beg, __end, __io, __err, __xtrc, 
+                    numeric_limits<unsigned long>::digits10, __base);
 
       // Stage 2: convert and store results.
       char* __sanity;
index c3572c40b1593674c614e60b5b4c7c711c68bf16..2a16a3aeed21499a69a0969ae79350062bcf607c 100644 (file)
@@ -74,7 +74,7 @@ namespace std
   // Definitions for static const data members of locale::id
   size_t locale::id::_S_highwater;  // init'd to 0 by linker
 
-  const char __num_base::_S_atoms[] = "0123456789eEabcdfxABCDFX";
+  const char __num_base::_S_atoms[] = "0123456789eEabcdfABCDF";
 
   // Definitions for static const data members of locale::_Impl
   const locale::id* const
index 0cb5ae0ed028374d0a43ca74efebe906b132dacd..9a8537e82f837c225d96b05e9fd92a2a123f0af0 100644 (file)
@@ -513,6 +513,83 @@ bool test11()
   return test;
 }
 
+// libstdc++/3720
+// excess input should not cause a core dump
+template<typename T>
+bool test12_aux(bool integer_type)
+{
+  bool test = true;
+  
+  int digits_overflow;
+  if (integer_type)
+    // This many digits will overflow integer types in base 10.
+    digits_overflow = std::numeric_limits<T>::digits10 + 1;
+  else
+    // This might do it, unsure.
+    digits_overflow = std::numeric_limits<T>::max_exponent10 + 1;
+  
+  std::string st;
+  std::string part = "1234567890123456789012345678901234567890";
+  for (int i = 0; i < digits_overflow / part.size() + 1; ++i)
+    st += part;
+  std::stringbuf sb(st);
+  std::istream is(&sb);
+  T t;
+  is >> t;
+  VERIFY(is.fail());
+  return test;
+}
+
+bool test12()
+{
+  bool test = true;
+  VERIFY(test12_aux<short>(true));
+  VERIFY(test12_aux<int>(true));
+  VERIFY(test12_aux<long>(true));
+  VERIFY(test12_aux<float>(false));
+  VERIFY(test12_aux<double>(false));
+  VERIFY(test12_aux<long double>(false));
+  return test;
+}
+
+// libstdc++/3720 part two
+void test13()
+{
+  using namespace std;
+  bool test = true;
+  const char* l1 = "12345678901234567890123456789012345678901234567890123456";
+  const char* l2 = "1.2345678901234567890123456789012345678901234567890123456"
+                   "  "
+                   "1246.9";
+
+  // 1 
+  // used to core.
+  double d;
+  istringstream iss1(l2);
+  iss1 >> d;
+  iss1 >> d;
+  VERIFY (d > 1246 && d < 1247);
+
+  // 2
+  // quick test for failbit on maximum length extraction.
+  int i;
+  int max_digits = numeric_limits<int>::digits10;
+  string digits;
+  for (int j = 0; j < max_digits; ++j)
+    digits += '1';
+  istringstream iss2(digits);
+  iss2 >> i;
+  VERIFY( iss2.good() );
+
+  digits += '1';
+  i = 0;
+  iss2.str(digits);
+  iss2.clear();
+  iss2 >> i; 
+  VERIFY( i == 0 );
+  VERIFY( iss2.fail() );
+}
+
 int main()
 {
   test01();
@@ -526,6 +603,7 @@ int main()
   test10();
   
   test11();
+  test12();
   return 0;
 }