]> gcc.gnu.org Git - gcc.git/commitdiff
re PR libstdc++/21209 (signed integer overflow in num_get<>::_M_extract_int)
authorPaolo Carlini <pcarlini@suse.de>
Tue, 26 Apr 2005 09:31:07 +0000 (09:31 +0000)
committerPaolo Carlini <paolo@gcc.gnu.org>
Tue, 26 Apr 2005 09:31:07 +0000 (09:31 +0000)
2005-04-26  Paolo Carlini  <pcarlini@suse.de>

PR libstdc++/21209
* include/bits/locale_facets.tcc (_M_extract_int): Avoid signed
integer overflow, always use a suited unsigned type in the main
parsing loop.
(struct __to_unsigned_type): New.
* testsuite/22_locale/num_get/get/char/16.cc: New.
* testsuite/22_locale/num_get/get/wchar_t/16.cc: Likewise.

From-SVN: r98768

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/locale_facets.tcc
libstdc++-v3/testsuite/22_locale/num_get/get/char/16.cc [new file with mode: 0644]
libstdc++-v3/testsuite/22_locale/num_get/get/wchar_t/16.cc [new file with mode: 0644]

index e150ad73f9423aebd3f3397955c35171bf0724d2..87a5cc6b9cbf31451acaf76f66270930243f9498 100644 (file)
@@ -1,3 +1,13 @@
+2005-04-26  Paolo Carlini  <pcarlini@suse.de>
+
+       PR libstdc++/21209
+       * include/bits/locale_facets.tcc (_M_extract_int): Avoid signed
+       integer overflow, always use a suited unsigned type in the main
+       parsing loop.
+       (struct __to_unsigned_type): New.
+       * testsuite/22_locale/num_get/get/char/16.cc: New.
+       * testsuite/22_locale/num_get/get/wchar_t/16.cc: Likewise.
+
 2005-04-25  Paolo Carlini  <pcarlini@suse.de>
 
        PR libstdc++/21035
index b558237ff47de36c4ebae8f10978a13ea75abeb4..436fe9d5b3122547be2b699deb79b8ccecaa807e 100644 (file)
@@ -440,6 +440,20 @@ namespace std
       return __beg;
     }
 
+  template<typename _ValueT>
+    struct __to_unsigned_type
+    { typedef _ValueT __type; };
+
+  template<>
+    struct __to_unsigned_type<long>
+    { typedef unsigned long __type; };
+
+#ifdef _GLIBCXX_USE_LONG_LONG
+  template<>
+    struct __to_unsigned_type<long long>
+    { typedef unsigned long long __type; };
+#endif
+
   template<typename _CharT, typename _InIter>
     template<typename _ValueT>
       _InIter
@@ -447,8 +461,9 @@ namespace std
       _M_extract_int(_InIter __beg, _InIter __end, ios_base& __io,
                     ios_base::iostate& __err, _ValueT& __v) const
       {
-        typedef char_traits<_CharT>                    __traits_type;
-       typedef typename numpunct<_CharT>::__cache_type __cache_type;
+        typedef char_traits<_CharT>                         __traits_type;
+       typedef typename __to_unsigned_type<_ValueT>::__type __unsigned_type;   
+       typedef typename numpunct<_CharT>::__cache_type      __cache_type;
        __use_cache<__cache_type> __uc;
        const locale& __loc = __io._M_getloc();
        const __cache_type* __lc = __uc(__loc);
@@ -536,103 +551,56 @@ namespace std
          __found_grouping.reserve(32);
        int __sep_pos = 0;
        bool __overflow = false;
-       _ValueT __result = 0;
+       const __unsigned_type __max = __negative ?
+         -numeric_limits<_ValueT>::min() : numeric_limits<_ValueT>::max();
+       const __unsigned_type __smax = __max / __base;
+       __unsigned_type __result = 0;
        const char_type* __q;
        const char_type* __lit_zero = __lit + __num_base::_S_izero;
-       if (__negative)
+       while (!__testeof)
          {
-           const _ValueT __min = numeric_limits<_ValueT>::min() / __base;
-           while (!__testeof)
+           // According to 22.2.2.1.2, p8-9, first look for thousands_sep
+           // and decimal_point.
+           if (__lc->_M_use_grouping && __c == __lc->_M_thousands_sep)
              {
-               // According to 22.2.2.1.2, p8-9, first look for thousands_sep
-               // and decimal_point.
-               if (__lc->_M_use_grouping && __c == __lc->_M_thousands_sep)
+               // NB: Thousands separator at the beginning of a string
+               // is a no-no, as is two consecutive thousands separators.
+               if (__sep_pos)
                  {
-                   // NB: Thousands separator at the beginning of a string
-                   // is a no-no, as is two consecutive thousands separators.
-                   if (__sep_pos)
-                     {
-                       __found_grouping += static_cast<char>(__sep_pos);
-                       __sep_pos = 0;
-                     }
-                   else
-                     {
-                       __err |= ios_base::failbit;
-                       break;
-                     }
+                   __found_grouping += static_cast<char>(__sep_pos);
+                   __sep_pos = 0;
                  }
-               else if (__c == __lc->_M_decimal_point)
-                 break;
-               else if ((__q = __traits_type::find(__lit_zero, __len, __c)))
+               else
                  {
-                   int __digit = __q - __lit_zero;
-                   if (__digit > 15)
-                     __digit -= 6;
-                   if (__result < __min)
-                     __overflow = true;
-                   else
-                     {
-                       const _ValueT __new_result = (__result * __base
-                                                     - __digit);
-                       __overflow |= __new_result > __result;
-                       __result = __new_result;
-                       ++__sep_pos;
-                     }
+                   __err |= ios_base::failbit;
+                   break;
                  }
-               else
-                 // Not a valid input item.
-                 break;
-
-               if (++__beg != __end)
-                 __c = *__beg;
-               else
-                 __testeof = true;
              }
-         }
-       else
-         {
-           const _ValueT __max = numeric_limits<_ValueT>::max() / __base;
-           while (!__testeof)
+           else if (__c == __lc->_M_decimal_point)
+             break;
+           else if ((__q = __traits_type::find(__lit_zero, __len, __c)))
              {
-               if (__lc->_M_use_grouping && __c == __lc->_M_thousands_sep)
-                 {
-                   if (__sep_pos)
-                     {
-                       __found_grouping += static_cast<char>(__sep_pos);
-                       __sep_pos = 0;
-                     }
-                   else
-                     {
-                       __err |= ios_base::failbit;
-                       break;
-                     }
-                 }
-               else if (__c == __lc->_M_decimal_point)
-                 break;
-               else if ((__q = __traits_type::find(__lit_zero, __len, __c)))
+               int __digit = __q - __lit_zero;
+               if (__digit > 15)
+                 __digit -= 6;
+               if (__result > __smax)
+                 __overflow = true;
+               else
                  {
-                   int __digit = __q - __lit_zero;
-                   if (__digit > 15)
-                     __digit -= 6;
-                   if (__result > __max)
-                     __overflow = true;
-                   else
-                     {
-                       const _ValueT __new_result = (__result * __base
-                                                     + __digit);
-                       __overflow |= __new_result < __result;
-                       __result = __new_result;
-                       ++__sep_pos;
-                     }
+                   __result *= __base;
+                   __overflow |= __result > __max - __digit;
+                   __result += __digit;
+                   ++__sep_pos;
                  }
-               else
-                 break;
-
-               if (++__beg != __end)
-                 __c = *__beg;
-               else
-                 __testeof = true;
              }
+           else
+             // Not a valid input item.              
+             break;
+           
+           if (++__beg != __end)
+             __c = *__beg;
+           else
+             __testeof = true;
          }
 
        // Digit grouping is checked. If grouping and found_grouping don't
@@ -650,7 +618,7 @@ namespace std
 
        if (!(__err & ios_base::failbit) && !__overflow
            && (__sep_pos || __found_zero || __found_grouping.size()))
-         __v = __result;
+         __v = __negative ? -__result : __result;
        else
          __err |= ios_base::failbit;
 
diff --git a/libstdc++-v3/testsuite/22_locale/num_get/get/char/16.cc b/libstdc++-v3/testsuite/22_locale/num_get/get/char/16.cc
new file mode 100644 (file)
index 0000000..0351271
--- /dev/null
@@ -0,0 +1,202 @@
+// 2005-04-26  Paolo Carlini  <pcarlini@suse.de>
+
+// Copyright (C) 2005 Free Software Foundation
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING.  If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 22.2.2.1.1  num_get members
+
+#include <locale>
+#include <sstream>
+#include <limits>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std;
+  typedef istreambuf_iterator<char> iterator_type;
+  
+  bool test __attribute__((unused)) = true;
+
+  stringstream ss;
+  const num_get<char>& ng = use_facet<num_get<char> >(ss.getloc()); 
+  ios_base::iostate err;
+  iterator_type end;
+
+  unsigned short us0, us1 = numeric_limits<unsigned short>::max();
+  unsigned int ui0, ui1 = numeric_limits<unsigned int>::max();
+  unsigned long ul0, ul1 = numeric_limits<unsigned long>::max();
+  long l01, l1 = numeric_limits<long>::max();
+  long l02, l2 = numeric_limits<long>::min();
+#ifdef _GLIBCXX_USE_LONG_LONG
+  unsigned long long ull0, ull1 = numeric_limits<unsigned long long>::max();
+  long long ll01, ll1 = numeric_limits<long long>::max();
+  long long ll02, ll2 = numeric_limits<long long>::min();
+#endif
+
+  const string empty;
+
+  us0 = 0;
+  ss << us1;
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, us0);
+  VERIFY( err == ios_base::eofbit );
+  VERIFY( us0 == us1 );
+
+  us0 = 0;
+  ss.clear();
+  ss.str(empty);
+  ss << us1 << '0';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, us0);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( us0 == 0 );
+
+  ui0 = 0U;
+  ss.clear();
+  ss.str(empty);
+  ss << ui1 << ' ';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ui0);
+  VERIFY( err == ios_base::goodbit );
+  VERIFY( ui0 == ui1 );
+
+  ui0 = 0U;
+  ss.clear();
+  ss.str(empty);
+  ss << ui1 << '1';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ui0);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ui0 == 0U );
+
+  ul0 = 0UL;
+  ss.clear();
+  ss.str(empty);
+  ss << ul1;
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ul0);
+  VERIFY( err == ios_base::eofbit );
+  VERIFY( ul0 == ul1 );
+
+  ul0 = 0UL;
+  ss.clear();
+  ss.str(empty);
+  ss << ul1 << '2';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ul0);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ul0 == 0UL );
+
+  l01 = 0L;
+  ss.clear();
+  ss.str(empty);
+  ss << l1 << ' ';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, l01);
+  VERIFY( err == ios_base::goodbit );
+  VERIFY( l01 == l1 );
+
+  l01 = 0L;
+  ss.clear();
+  ss.str(empty);
+  ss << l1 << '3';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, l01);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( l01 == 0L );
+
+  l02 = 0L;
+  ss.clear();
+  ss.str(empty);
+  ss << l2;
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, l02);
+  VERIFY( err == ios_base::eofbit );
+  VERIFY( l02 == l2 );
+
+  l02 = 0L;
+  ss.clear();
+  ss.str(empty);
+  ss << l2 << '4';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, l02);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( l02 == 0L );
+
+#ifdef _GLIBCXX_USE_LONG_LONG
+  ull0 = 0ULL;
+  ss.clear();
+  ss.str(empty);
+  ss << ull1 << ' ';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ull0);
+  VERIFY( err == ios_base::goodbit );
+  VERIFY( ull0 == ull1 );
+
+  ull0 = 0ULL;
+  ss.clear();
+  ss.str(empty);
+  ss << ull1 << '5';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ull0);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ull0 == 0ULL );
+
+  ll01 = 0LL;
+  ss.clear();
+  ss.str(empty);
+  ss << ll1;
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ll01);
+  VERIFY( err == ios_base::eofbit );
+  VERIFY( ll01 == ll1 );
+
+  ll01 = 0LL;
+  ss.clear();
+  ss.str(empty);
+  ss << ll1 << '6';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ll01);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ll01 == 0LL );
+
+  ll02 = 0LL;
+  ss.clear();
+  ss.str(empty);
+  ss << ll2 << ' ';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ll02);
+  VERIFY( err == ios_base::goodbit );
+  VERIFY( ll02 == ll2 );
+
+  ll02 = 0LL;
+  ss.clear();
+  ss.str(empty);
+  ss << ll2 << '7';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ll02);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ll02 == 0LL );
+#endif
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
diff --git a/libstdc++-v3/testsuite/22_locale/num_get/get/wchar_t/16.cc b/libstdc++-v3/testsuite/22_locale/num_get/get/wchar_t/16.cc
new file mode 100644 (file)
index 0000000..ca774da
--- /dev/null
@@ -0,0 +1,202 @@
+// 2005-04-26  Paolo Carlini  <pcarlini@suse.de>
+
+// Copyright (C) 2005 Free Software Foundation
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 2, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING.  If not, write to the Free
+// Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+// USA.
+
+// 22.2.2.1.1  num_get members
+
+#include <locale>
+#include <sstream>
+#include <limits>
+#include <testsuite_hooks.h>
+
+void test01()
+{
+  using namespace std;
+  typedef istreambuf_iterator<wchar_t> iterator_type;
+  
+  bool test __attribute__((unused)) = true;
+
+  wstringstream ss;
+  const num_get<wchar_t>& ng = use_facet<num_get<wchar_t> >(ss.getloc()); 
+  ios_base::iostate err;
+  iterator_type end;
+
+  unsigned short us0, us1 = numeric_limits<unsigned short>::max();
+  unsigned int ui0, ui1 = numeric_limits<unsigned int>::max();
+  unsigned long ul0, ul1 = numeric_limits<unsigned long>::max();
+  long l01, l1 = numeric_limits<long>::max();
+  long l02, l2 = numeric_limits<long>::min();
+#ifdef _GLIBCXX_USE_LONG_LONG
+  unsigned long long ull0, ull1 = numeric_limits<unsigned long long>::max();
+  long long ll01, ll1 = numeric_limits<long long>::max();
+  long long ll02, ll2 = numeric_limits<long long>::min();
+#endif
+
+  const wstring empty;
+
+  us0 = 0;
+  ss << us1;
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, us0);
+  VERIFY( err == ios_base::eofbit );
+  VERIFY( us0 == us1 );
+
+  us0 = 0;
+  ss.clear();
+  ss.str(empty);
+  ss << us1 << L'0';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, us0);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( us0 == 0 );
+
+  ui0 = 0U;
+  ss.clear();
+  ss.str(empty);
+  ss << ui1 << ' ';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ui0);
+  VERIFY( err == ios_base::goodbit );
+  VERIFY( ui0 == ui1 );
+
+  ui0 = 0U;
+  ss.clear();
+  ss.str(empty);
+  ss << ui1 << L'1';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ui0);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ui0 == 0U );
+
+  ul0 = 0UL;
+  ss.clear();
+  ss.str(empty);
+  ss << ul1;
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ul0);
+  VERIFY( err == ios_base::eofbit );
+  VERIFY( ul0 == ul1 );
+
+  ul0 = 0UL;
+  ss.clear();
+  ss.str(empty);
+  ss << ul1 << L'2';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ul0);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ul0 == 0UL );
+
+  l01 = 0L;
+  ss.clear();
+  ss.str(empty);
+  ss << l1 << L' ';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, l01);
+  VERIFY( err == ios_base::goodbit );
+  VERIFY( l01 == l1 );
+
+  l01 = 0L;
+  ss.clear();
+  ss.str(empty);
+  ss << l1 << L'3';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, l01);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( l01 == 0L );
+
+  l02 = 0L;
+  ss.clear();
+  ss.str(empty);
+  ss << l2;
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, l02);
+  VERIFY( err == ios_base::eofbit );
+  VERIFY( l02 == l2 );
+
+  l02 = 0L;
+  ss.clear();
+  ss.str(empty);
+  ss << l2 << L'4';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, l02);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( l02 == 0L );
+
+#ifdef _GLIBCXX_USE_LONG_LONG
+  ull0 = 0ULL;
+  ss.clear();
+  ss.str(empty);
+  ss << ull1 << L' ';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ull0);
+  VERIFY( err == ios_base::goodbit );
+  VERIFY( ull0 == ull1 );
+
+  ull0 = 0ULL;
+  ss.clear();
+  ss.str(empty);
+  ss << ull1 << L'5';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ull0);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ull0 == 0ULL );
+
+  ll01 = 0LL;
+  ss.clear();
+  ss.str(empty);
+  ss << ll1;
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ll01);
+  VERIFY( err == ios_base::eofbit );
+  VERIFY( ll01 == ll1 );
+
+  ll01 = 0LL;
+  ss.clear();
+  ss.str(empty);
+  ss << ll1 << L'6';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ll01);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ll01 == 0LL );
+
+  ll02 = 0LL;
+  ss.clear();
+  ss.str(empty);
+  ss << ll2 << L' ';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ll02);
+  VERIFY( err == ios_base::goodbit );
+  VERIFY( ll02 == ll2 );
+
+  ll02 = 0LL;
+  ss.clear();
+  ss.str(empty);
+  ss << ll2 << L'7';
+  err = ios_base::goodbit;
+  end = ng.get(ss.rdbuf(), 0, ss, err, ll02);
+  VERIFY( err == (ios_base::failbit | ios_base::eofbit) );
+  VERIFY( ll02 == 0LL );
+#endif
+}
+
+int main()
+{
+  test01();
+  return 0;
+}
This page took 0.084774 seconds and 5 git commands to generate.