libstdc++/3720: Problems with num_get
Philip Martin
philip@codematters.co.uk
Mon Dec 10 16:57:00 GMT 2001
Benjamin Kosnik <bkoz@redhat.com> writes:
> Peter, I'd like this to be fixed on the branch, but I am unable to work
> on this right now due to pending deadlines elsewhere.
>
> Porting the patch to gcc-3.0 might be possible, but for gcc-3.03 you'd
> have to be binary-compatibile with gcc-3.02, and it's solved in mainline
> without this additional constraint.
Here's a simple patch (with no ABI change I believe) that avoids the
buffer overflow, it sets failbit intead. It's not strictly ISO
compliant, as some valid input longer than the buffer sets failbit
instead of being read successfully, but that might be better than
dumping core. All integer input should be handled correctly. Only
floating-point input more than 31 characters, after discarding leading
zeros, can exceed the buffer.
Philip
libstdc++/3720: Designed for the 3.0 branch. This in strictly
non-compliant but it's probably better than dumping core.
* include/bits/locale_facets.h
(_M_extract_buffer_length): Add this constant.
* include/bits/locale_facet.tcc
(do_get): Use _M_extract_buffer_length.
* src/locale.cc
(_M_extract): Set failbit if buffer gets filled while
extracting characters.
* testsuite/27_io/istream_extractor_arith.cc
(tes12_aux, test12, test13): Add, ported from trunk.
Index: include/bits/locale_facets.h
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/locale_facets.h,v
retrieving revision 1.12.2.2
diff -c -3 -p -r1.12.2.2 locale_facets.h
*** locale_facets.h 2001/06/04 19:30:55 1.12.2.2
--- locale_facets.h 2001/12/11 00:37:28
*************** namespace std
*** 561,566 ****
--- 561,569 ----
_M_get_digits(iter_type __in, iter_type __end) const;
};
+ // This is the size of the buffer passed to _M_extract
+ const int _M_extract_buffer_length = 32;
+
template<typename _CharT, typename _InIter>
class num_get : public locale::facet
{
Index: include/bits/locale_facets.tcc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/include/bits/locale_facets.tcc,v
retrieving revision 1.8.2.4
diff -c -3 -p -r1.8.2.4 locale_facets.tcc
*** locale_facets.tcc 2001/06/10 23:41:55 1.8.2.4
--- locale_facets.tcc 2001/12/11 00:37:28
*************** namespace std
*** 282,288 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32] = {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 282,288 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length] = {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
*************** namespace std
*** 347,353 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 347,353 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
*************** namespace std
*** 374,380 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32] = {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 374,380 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length] = {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
*************** namespace std
*** 402,408 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 402,408 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
*************** namespace std
*** 429,435 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 429,435 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
*************** namespace std
*** 456,462 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 456,462 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
*************** namespace std
*** 483,489 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 483,489 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
*************** namespace std
*** 510,516 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32] = {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 510,516 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length] = {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
*************** namespace std
*** 537,543 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 537,543 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
*************** namespace std
*** 564,570 ****
// 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'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, true);
--- 564,570 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 256 for
// floating-point types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, true);
*************** namespace std
*** 594,600 ****
// 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'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, true);
--- 594,600 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 256 for
// floating-point types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, true);
*************** namespace std
*** 621,627 ****
// 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'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, true);
--- 621,627 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 256 for
// floating-point types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, true);
*************** namespace std
*** 645,651 ****
ios_base::iostate& __err, long double& __v) const
{
// Stage 1: extract
! char __xtrc[32]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, true);
--- 645,651 ----
ios_base::iostate& __err, long double& __v) const
{
// Stage 1: extract
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, true);
*************** namespace std
*** 691,697 ****
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[32]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
--- 691,697 ----
// Stage 1: extract and determine the conversion specifier.
// Assuming leading zeros eliminated, thus the size of 32 for
// integral types.
! char __xtrc[_M_extract_buffer_length]= {'\0'};
int __base;
_M_extract(__beg, __end, __io, __err, __xtrc, __base, false);
Index: src/locale.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/src/locale.cc,v
retrieving revision 1.28.2.4
diff -c -3 -p -r1.28.2.4 locale.cc
*** locale.cc 2001/07/20 00:14:10 1.28.2.4
--- locale.cc 2001/12/11 00:37:29
*************** namespace std
*** 646,651 ****
--- 646,657 ----
}
#endif
+ // This interface passes a fixed size buffer. The function cannot handle
+ // input longer than the buffer and sets failbit in that case. This is
+ // not strictly compliant since the input may be valid, but we are stuck
+ // with this ABI on the 3.0 branch. Since leading zeros are discarded all
+ // valid integer input should be OK, only floating point input can exceed
+ // the buffer.
template<>
void
num_get<char, istreambuf_iterator<char> >::
*************** namespace std
*** 785,790 ****
--- 791,804 ----
{
// Try first for acceptable digit; record it if found.
__xtrc[__pos++] = __c;
+ if (__pos == _M_extract_buffer_length)
+ {
+ // XXX This is non-compliant, but our fixed-size
+ // buffer is full.
+ __xtrc[_M_extract_buffer_length-1] = '\0';
+ __err |= ios_base::failbit;
+ return;
+ }
++__sep_pos;
__testunits = true;
++__beg;
*************** namespace std
*** 865,870 ****
--- 879,892 ----
if (__c == __fmt->_M_decimal_point)
{
__xtrc[__pos++] = '.';
+ if (__pos == _M_extract_buffer_length)
+ {
+ // XXX This is non-compliant, but our fixed-size
+ // buffer is full.
+ __xtrc[_M_extract_buffer_length-1] = '\0';
+ __err |= ios_base::failbit;
+ return;
+ }
++__beg;
__c = *__beg;
*************** namespace std
*** 879,884 ****
--- 901,914 ----
&& __p < &__lits[__cache_type::_S_udigits + __base]))
{
__xtrc[__pos++] = __c;
+ if (__pos == _M_extract_buffer_length)
+ {
+ // XXX This is non-compliant, but our fixed-size
+ // buffer is full.
+ __xtrc[_M_extract_buffer_length-1] = '\0';
+ __err |= ios_base::failbit;
+ return;
+ }
++__beg;
__c = *__beg;
__testdec = true;
*************** namespace std
*** 903,908 ****
--- 933,946 ----
|| (__c == __lits[__cache_type::_S_Ee]))
{
__xtrc[__pos++] = __c;
+ if (__pos == _M_extract_buffer_length)
+ {
+ // XXX This is non-compliant, but our fixed-size
+ // buffer is full.
+ __xtrc[_M_extract_buffer_length-1] = '\0';
+ __err |= ios_base::failbit;
+ return;
+ }
++__beg;
__c = *__beg;
*************** namespace std
*** 913,918 ****
--- 951,964 ----
|| (__c == __lits[__cache_type::_S_plus]))
{
__xtrc[__pos++] = __c;
+ if (__pos == _M_extract_buffer_length)
+ {
+ // XXX This is non-compliant, but our fixed-size
+ // buffer is full.
+ __xtrc[_M_extract_buffer_length-1] = '\0';
+ __err |= ios_base::failbit;
+ return;
+ }
++__beg;
__c = *__beg;
// whitespace may follow a sign
*************** namespace std
*** 939,944 ****
--- 985,998 ----
&& __p < &__lits[__cache_type::_S_udigits + __base]))
{
__xtrc[__pos++] = __c;
+ if (__pos == _M_extract_buffer_length)
+ {
+ // XXX This is non-compliant, but our fixed-size
+ // buffer is full.
+ __xtrc[_M_extract_buffer_length-1] = '\0';
+ __err |= ios_base::failbit;
+ return;
+ }
++__beg;
__c = *__beg;
}
Index: testsuite/27_io/istream_extractor_arith.cc
===================================================================
RCS file: /cvs/gcc/gcc/libstdc++-v3/testsuite/27_io/istream_extractor_arith.cc,v
retrieving revision 1.8.4.2
diff -c -3 -p -r1.8.4.2 istream_extractor_arith.cc
*** istream_extractor_arith.cc 2001/08/28 21:19:09 1.8.4.2
--- istream_extractor_arith.cc 2001/12/11 00:37:29
*************** bool test11()
*** 513,518 ****
--- 513,596 ----
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;
+ // XXX doesn't work on 3.0 branch
+ // 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.fail() );
+
+ digits += '1';
+ i = 0;
+ iss2.str(digits);
+ iss2.clear();
+ iss2 >> i;
+ VERIFY( i == 0 );
+ VERIFY( iss2.fail() );
+ }
+
int main()
{
test01();
*************** int main()
*** 526,531 ****
--- 604,611 ----
test10();
test11();
+ test12();
+ test13();
return 0;
}
More information about the Gcc-bugs
mailing list