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
This commit is contained in:
Paolo Carlini 2005-04-26 09:31:07 +00:00 committed by Paolo Carlini
parent c579626684
commit 44ecf60364
4 changed files with 471 additions and 89 deletions

View 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

View 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;
}
}
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 < __min)
__overflow = true;
else
{
const _ValueT __new_result = (__result * __base
- __digit);
__overflow |= __new_result > __result;
__result = __new_result;
++__sep_pos;
}
__found_grouping += static_cast<char>(__sep_pos);
__sep_pos = 0;
}
else
// Not a valid input item.
break;
if (++__beg != __end)
__c = *__beg;
else
__testeof = true;
{
__err |= ios_base::failbit;
break;
}
}
}
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 > __max)
__overflow = true;
else
{
const _ValueT __new_result = (__result * __base
+ __digit);
__overflow |= __new_result < __result;
__result = __new_result;
++__sep_pos;
}
}
int __digit = __q - __lit_zero;
if (__digit > 15)
__digit -= 6;
if (__result > __smax)
__overflow = true;
else
break;
if (++__beg != __end)
__c = *__beg;
else
__testeof = true;
{
__result *= __base;
__overflow |= __result > __max - __digit;
__result += __digit;
++__sep_pos;
}
}
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;

View File

@ -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;
}

View File

@ -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;
}