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 /libstdc++-v3/include | |
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
Diffstat (limited to 'libstdc++-v3/include')
-rw-r--r-- | libstdc++-v3/include/bits/locale_facets.tcc | 142 |
1 files changed, 55 insertions, 87 deletions
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; |