diff options
author | Paolo Carlini <pcarlini@suse.de> | 2005-04-26 09:31:07 +0000 |
---|---|---|
committer | Paolo Carlini <paolo@gcc.gnu.org> | 2005-04-26 09:31:07 +0000 |
commit | 44ecf603649098d1d89bd855155a215507bf9e86 (patch) | |
tree | 90e9886d6ee581f71733aa43b16029cbbf1fb27a | |
parent | c579626684c724b226892b0869316fd1ed7ad350 (diff) | |
download | gcc-44ecf603649098d1d89bd855155a215507bf9e86.zip gcc-44ecf603649098d1d89bd855155a215507bf9e86.tar.gz gcc-44ecf603649098d1d89bd855155a215507bf9e86.tar.bz2 |
re PR libstdc++/21209 (signed integer overflow in num_get<>::_M_extract_int)
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
-rw-r--r-- | libstdc++-v3/ChangeLog | 10 | ||||
-rw-r--r-- | libstdc++-v3/include/bits/locale_facets.tcc | 142 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/22_locale/num_get/get/char/16.cc | 202 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/22_locale/num_get/get/wchar_t/16.cc | 202 |
4 files changed, 469 insertions, 87 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index e150ad7..87a5cc6 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -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 diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc index b558237..436fe9d 100644 --- a/libstdc++-v3/include/bits/locale_facets.tcc +++ b/libstdc++-v3/include/bits/locale_facets.tcc @@ -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 index 0000000..0351271 --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/num_get/get/char/16.cc @@ -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 index 0000000..ca774da --- /dev/null +++ b/libstdc++-v3/testsuite/22_locale/num_get/get/wchar_t/16.cc @@ -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; +} |