From 823b4f7daa4141d9986e8df7308f1d7fb19e03a8 Mon Sep 17 00:00:00 2001 From: Benjamin Kosnik Date: Fri, 7 Dec 2001 02:58:36 +0000 Subject: [PATCH] [multiple changes] 2001-12-06 Benjamin Kosnik libstdc++/3720 * include/bits/locale_facets.tcc (num_put): Clean. (num_get::_M_extract_float): Change argument to string. (num_get::do_get(float)): Fixup. (num_get::do_get(double)): Same. (num_get::do_get(long double)): Same. (num_get::_M_extract_int): Add maximum length parameter, __max. (num_get::_M_extract_float): Correct zeros, use string. * include/bits/locale_facets.h (num_get::_M_extract_float): Change declaration here. * src/locale.cc (__num_base::_S_atoms): Remove x, X. * testsuite/27_io/istream_extractor_arith.cc (test13): Add. 2001-12-06 Philip Martin * testsuite/27_io/istream_extractor_arith.cc (test12): Add tests for excess input digits. From-SVN: r47743 --- libstdc++-v3/ChangeLog | 22 +- libstdc++-v3/include/bits/locale_facets.h | 8 +- libstdc++-v3/include/bits/locale_facets.tcc | 205 +++++++++++------- libstdc++-v3/src/locale.cc | 2 +- .../27_io/istream_extractor_arith.cc | 78 +++++++ 5 files changed, 226 insertions(+), 89 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index b5dfa19c71e..4348d33f44d 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,23 @@ +2001-12-06 Benjamin Kosnik + + libstdc++/3720 + * include/bits/locale_facets.tcc (num_put): Clean. + (num_get::_M_extract_float): Change argument to string. + (num_get::do_get(float)): Fixup. + (num_get::do_get(double)): Same. + (num_get::do_get(long double)): Same. + (num_get::_M_extract_int): Add maximum length parameter, __max. + (num_get::_M_extract_float): Correct zeros, use string. + * include/bits/locale_facets.h (num_get::_M_extract_float): Change + declaration here. + * src/locale.cc (__num_base::_S_atoms): Remove x, X. + * testsuite/27_io/istream_extractor_arith.cc (test13): Add. + +2001-12-06 Philip Martin + + * testsuite/27_io/istream_extractor_arith.cc (test12): Add + tests for excess input digits. + 2001-12-06 Phil Edwards * include/bits/std_bitset.h: Use GLIBCPP in multiple-inclusion guard. @@ -42,7 +62,7 @@ 2001-12-04 Paolo Carlini libstdc++/4402 - * testsuite/27_io/ostream_inserter_arith.cc (test02): add testcase + * testsuite/27_io/ostream_inserter_arith.cc (test02): Add testcase from the PR. * include/bits/locale_facets.tcc (num_put::_M_convert_float): Deal properly with long ios_base::fixed floats. diff --git a/libstdc++-v3/include/bits/locale_facets.h b/libstdc++-v3/include/bits/locale_facets.h index 878f8b28cab..27bd5b15ac7 100644 --- a/libstdc++-v3/include/bits/locale_facets.h +++ b/libstdc++-v3/include/bits/locale_facets.h @@ -420,7 +420,7 @@ namespace std { public: // String literal of acceptable (narrow) input, for num_get. - // "0123456789eEabcdfxABCDFX" + // "0123456789eEabcdfABCDF" static const char _S_atoms[]; enum @@ -428,7 +428,7 @@ namespace std _M_zero, _M_e = _M_zero + 10, _M_E = _M_zero + 11, - _M_size = 23 + 1 + _M_size = 21 + 1 }; // Construct and return valid scanf format for floating point types. @@ -634,11 +634,11 @@ namespace std void _M_extract_float(iter_type, iter_type, ios_base&, ios_base::iostate&, - char* __xtrc) const; + string& __xtrc) const; void _M_extract_int(iter_type, iter_type, ios_base&, ios_base::iostate&, - char* __xtrc, int& __base) const; + char* __xtrc, int __max, int& __base) const; virtual iter_type do_get(iter_type, iter_type, ios_base&, ios_base::iostate&, bool&) const; diff --git a/libstdc++-v3/include/bits/locale_facets.tcc b/libstdc++-v3/include/bits/locale_facets.tcc index 95cbee5d8f1..363ff8b54a0 100644 --- a/libstdc++-v3/include/bits/locale_facets.tcc +++ b/libstdc++-v3/include/bits/locale_facets.tcc @@ -35,6 +35,7 @@ #include #include // For localeconv #include // For strof, strtold +#include // For ceil #include // For numeric_limits #include // For auto_ptr #include // For streambuf_iterators @@ -90,20 +91,21 @@ namespace std void num_get<_CharT, _InIter>:: _M_extract_float(_InIter __beg, _InIter __end, ios_base& __io, - ios_base::iostate& __err, char* __xtrc) const + ios_base::iostate& __err, string& __xtrc) const { const locale __loc = __io.getloc(); const ctype<_CharT>& __ctype = use_facet >(__loc); const numpunct<_CharT>& __np = use_facet >(__loc); - int __pos = 0; - char_type __c = *__beg; // Check first for sign. const char_type __plus = __ctype.widen('+'); const char_type __minus = __ctype.widen('-'); + int __pos = 0; + char_type __c = *__beg; if ((__c == __plus || __c == __minus) && __beg != __end) { - __xtrc[__pos++] = __ctype.narrow(__c, char()); + __xtrc += __ctype.narrow(__c, char()); + ++__pos; __c = *(++__beg); } @@ -116,7 +118,10 @@ namespace std __found_zero = true; } if (__found_zero) - __xtrc[__pos++] = _S_atoms[_M_zero]; + { + __xtrc += _S_atoms[_M_zero]; + ++__pos; + } // Only need acceptable digits for floating point numbers. const size_t __len = _M_E - _M_zero + 1; @@ -142,7 +147,8 @@ namespace std if (__p && __c) { // Try first for acceptable digit; record it if found. - __xtrc[__pos++] = _S_atoms[__p - __watoms]; + ++__pos; + __xtrc += _S_atoms[__p - __watoms]; ++__sep_pos; __c = *(++__beg); } @@ -165,7 +171,8 @@ namespace std else if (__c == __dec && !__found_dec) { __found_grouping += static_cast(__sep_pos); - __xtrc[__pos++] = '.'; + ++__pos; + __xtrc += '.'; __c = *(++__beg); __found_dec = true; } @@ -173,13 +180,15 @@ namespace std && !__found_sci && __pos) { // Scientific notation. - __xtrc[__pos++] = __ctype.narrow(__c, char()); + ++__pos; + __xtrc += __ctype.narrow(__c, char()); __c = *(++__beg); // Remove optional plus or minus sign, if they exist. if (__c == __plus || __c == __minus) { - __xtrc[__pos++] = __ctype.narrow(__c, char()); + ++__pos; + __xtrc += __ctype.narrow(__c, char()); __c = *(++__beg); } __found_sci = true; @@ -196,19 +205,12 @@ namespace std // Add the ending grouping if a decimal wasn't found. if (!__found_dec) __found_grouping += static_cast(__sep_pos); - if (!__verify_grouping(__grouping, __found_grouping)) - { - __err |= ios_base::failbit; - __xtrc[__pos] = '\0'; - if (__beg == __end) - __err |= ios_base::eofbit; - return; - } + __err |= ios_base::failbit; } // Finish up - __xtrc[__pos] = char_type(); + __xtrc += char(); if (__beg == __end) __err |= ios_base::eofbit; } @@ -217,9 +219,15 @@ namespace std void num_get<_CharT, _InIter>:: _M_extract_int(_InIter __beg, _InIter __end, ios_base& __io, - ios_base::iostate& __err, char* __xtrc, int& __base) const + ios_base::iostate& __err, char* __xtrc, int __max, + int& __base) const { + const locale __loc = __io.getloc(); + const ctype<_CharT>& __ctype = use_facet >(__loc); + const numpunct<_CharT>& __np = use_facet >(__loc); + // Stage 1: determine a conversion specifier. + // NB: Iff __basefield == 0, this can change based on contents. ios_base::fmtflags __basefield = __io.flags() & ios_base::basefield; if (__basefield == ios_base::oct) __base = 8; @@ -228,13 +236,9 @@ namespace std else __base = 10; - const locale __loc = __io.getloc(); - const ctype<_CharT>& __ctype = use_facet >(__loc); - const numpunct<_CharT>& __np = use_facet >(__loc); + // Check first for sign. int __pos = 0; char_type __c = *__beg; - - // Check first for sign. if ((__c == __ctype.widen('+') || __c == __ctype.widen('-')) && __beg != __end) { @@ -242,24 +246,45 @@ namespace std __c = *(++__beg); } - // Next, strip leading zeros + // Next, strip leading zeros and check required digits for base formats. const char_type __zero = __ctype.widen(_S_atoms[_M_zero]); - bool __found_zero = false; - while (__base == 10 && __c == __zero && __beg != __end) + const char_type __x = __ctype.widen('x'); + const char_type __X = __ctype.widen('X'); + if (__base == 10) { - __c = *(++__beg); - __found_zero = true; + bool __found_zero = false; + while (__c == __zero && __beg != __end) + { + __c = *(++__beg); + __found_zero = true; + } + if (__found_zero) + { + __xtrc[__pos++] = _S_atoms[_M_zero]; + if (__basefield == 0) + { + if ((__c == __x || __c == __X) && __beg != __end) + { + __xtrc[__pos++] = __ctype.narrow(__c, char()); + __c = *(++__beg); + __base = 16; + } + else + __base = 8; + } + } } - if (__found_zero) + else if (__base == 16) { - __xtrc[__pos++] = _S_atoms[_M_zero]; - if (__basefield == 0) + if (__c == __zero && __beg != __end) { - // Depending on what is discovered, the base may change. - if (__c == __ctype.widen('x') || __c == __ctype.widen('X')) - __base = 16; - else - __base = 8; + __xtrc[__pos++] = _S_atoms[_M_zero]; + __c = *(++__beg); + if ((__c == __x || __c == __X) && __beg != __end) + { + __xtrc[__pos++] = __ctype.narrow(__c, char()); + __c = *(++__beg); + } } } @@ -271,14 +296,26 @@ namespace std else __len = __base; - char_type __watoms[_M_size]; + // Figure out the maximum number of digits that can be extracted + // for the given type, using the determined base. + int __max_digits; + if (__base != 10) + __max_digits = static_cast(ceil(__max * log(10.0) + /log(static_cast(__base)))); + else + __max_digits = __max; + // Add in what's already been extracted. + __max_digits += __pos; + + // Extract. + char_type __watoms[_M_size]; __ctype.widen(_S_atoms, _S_atoms + __len, __watoms); string __found_grouping; const string __grouping = __np.grouping(); bool __check_grouping = __grouping.size() && __base == 10; int __sep_pos = 0; const char_type __sep = __np.thousands_sep(); - while (__beg != __end) + while (__beg != __end && __pos <= __max_digits) { typedef char_traits<_CharT> __traits_type; const char_type* __p = __traits_type::find(__watoms, __len, __c); @@ -312,25 +349,22 @@ namespace std break; } + // If one more than the maximum number of digits is extracted. + if (__pos > __max_digits) + __err |= ios_base::failbit; + // Digit grouping is checked. If grouping and found_grouping don't // match, then get very very upset, and set failbit. if (__check_grouping && __found_grouping.size()) { - // Add the ending grouping + // Add the ending grouping. __found_grouping += static_cast(__sep_pos); - if (!__verify_grouping(__grouping, __found_grouping)) - { - __err |= ios_base::failbit; - __xtrc[__pos] = '\0'; - if (__beg == __end) - __err |= ios_base::eofbit; - return; - } + __err |= ios_base::failbit; } // Finish up - __xtrc[__pos] = char_type(); + __xtrc[__pos] = char(); if (__beg == __end) __err |= ios_base::eofbit; } @@ -351,10 +385,11 @@ namespace std // Stage 1: extract and determine the conversion specifier. // Assuming leading zeros eliminated, thus the size of 32 for - // integral types. - char __xtrc[32] = {'\0'}; + // integral types + char __xtrc[32]; int __base; - _M_extract_int(__beg, __end, __io, __err, __xtrc, __base); + _M_extract_int(__beg, __end, __io, __err, __xtrc, + numeric_limits::digits10, __base); // Stage 2: convert and store results. char* __sanity; @@ -416,9 +451,10 @@ namespace std // Stage 1: extract and determine the conversion specifier. // Assuming leading zeros eliminated, thus the size of 32 for // integral types. - char __xtrc[32]= {'\0'}; + char __xtrc[32]; int __base; - _M_extract_int(__beg, __end, __io, __err, __xtrc, __base); + _M_extract_int(__beg, __end, __io, __err, __xtrc, + numeric_limits::digits10, __base); // Stage 2: convert and store results. char* __sanity; @@ -441,9 +477,10 @@ namespace std // Stage 1: extract and determine the conversion specifier. // Assuming leading zeros eliminated, thus the size of 32 for // integral types. - char __xtrc[32]= {'\0'}; + char __xtrc[32]; int __base; - _M_extract_int(__beg, __end, __io, __err, __xtrc, __base); + _M_extract_int(__beg, __end, __io, __err, __xtrc, + numeric_limits::digits10, __base); // Stage 2: convert and store results. char* __sanity; @@ -467,9 +504,10 @@ namespace std // Stage 1: extract and determine the conversion specifier. // Assuming leading zeros eliminated, thus the size of 32 for // integral types. - char __xtrc[32]= {'\0'}; + char __xtrc[32]; int __base; - _M_extract_int(__beg, __end, __io, __err, __xtrc, __base); + _M_extract_int(__beg, __end, __io, __err, __xtrc, + numeric_limits::digits10, __base); // Stage 2: convert and store results. char* __sanity; @@ -493,9 +531,10 @@ namespace std // Stage 1: extract and determine the conversion specifier. // Assuming leading zeros eliminated, thus the size of 32 for // integral types. - char __xtrc[32] = {'\0'}; + char __xtrc[32]; int __base; - _M_extract_int(__beg, __end, __io, __err, __xtrc, __base); + _M_extract_int(__beg, __end, __io, __err, __xtrc, + numeric_limits::digits10, __base); // Stage 2: convert and store results. char* __sanity; @@ -519,9 +558,10 @@ namespace std // Stage 1: extract and determine the conversion specifier. // Assuming leading zeros eliminated, thus the size of 32 for // integral types. - char __xtrc[32]= {'\0'}; + char __xtrc[32]; int __base; - _M_extract_int(__beg, __end, __io, __err, __xtrc, __base); + _M_extract_int(__beg, __end, __io, __err, __xtrc, + numeric_limits::digits10, __base); // Stage 2: convert and store results. char* __sanity; @@ -544,9 +584,10 @@ namespace std // Stage 1: extract and determine the conversion specifier. // Assuming leading zeros eliminated, thus the size of 32 for // integral types. - char __xtrc[32]= {'\0'}; + char __xtrc[32]; int __base; - _M_extract_int(__beg, __end, __io, __err, __xtrc, __base); + _M_extract_int(__beg, __end, __io, __err, __xtrc, + numeric_limits::digits10, __base); // Stage 2: convert and store results. char* __sanity; @@ -568,21 +609,20 @@ namespace std ios_base::iostate& __err, float& __v) const { // 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'}; + string __xtrc; + __xtrc.reserve(32); _M_extract_float(__beg, __end, __io, __err, __xtrc); // Stage 2: convert and store results. char* __sanity; errno = 0; #ifdef _GLIBCPP_USE_C99 - float __f = strtof(__xtrc, &__sanity); + float __f = strtof(__xtrc.c_str(), &__sanity); #else - float __f = static_cast(strtod(__xtrc, &__sanity)); + float __f = static_cast(strtod(__xtrc.c_str(), &__sanity)); #endif if (!(__err & ios_base::failbit) - && __sanity != __xtrc && *__sanity == '\0' && errno == 0) + && __sanity != __xtrc.c_str() && *__sanity == '\0' && errno == 0) __v = __f; else __err |= ios_base::failbit; @@ -596,17 +636,16 @@ namespace std ios_base::iostate& __err, double& __v) const { // 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'}; + string __xtrc; + __xtrc.reserve(32); _M_extract_float(__beg, __end, __io, __err, __xtrc); // Stage 2: convert and store results. char* __sanity; errno = 0; - double __d = strtod(__xtrc, &__sanity); + double __d = strtod(__xtrc.c_str(), &__sanity); if (!(__err & ios_base::failbit) - && __sanity != __xtrc && *__sanity == '\0' && errno == 0) + && __sanity != __xtrc.c_str() && *__sanity == '\0' && errno == 0) __v = __d; else __err |= ios_base::failbit; @@ -620,18 +659,17 @@ namespace std ios_base::iostate& __err, long double& __v) const { // 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'}; + string __xtrc; + __xtrc.reserve(32); _M_extract_float(__beg, __end, __io, __err, __xtrc); #if defined(_GLIBCPP_USE_C99) && !defined(__hpux) // Stage 2: convert and store results. char* __sanity; errno = 0; - long double __ld = strtold(__xtrc, &__sanity); + long double __ld = strtold(__xtrc.c_str(), &__sanity); if (!(__err & ios_base::failbit) - && __sanity != __xtrc && *__sanity == '\0' && errno == 0) + && __sanity != __xtrc.c_str() && *__sanity == '\0' && errno == 0) __v = __ld; #else // Stage 2: determine a conversion specifier. @@ -649,7 +687,7 @@ namespace std // Stage 3: store results. typedef typename char_traits<_CharT>::int_type int_type; long double __ld; - int __p = sscanf(__xtrc, __conv, &__ld); + int __p = sscanf(__xtrc.c_str(), __conv, &__ld); if (!(__err & ios_base::failbit) && __p && static_cast(__p) != char_traits<_CharT>::eof()) __v = __ld; @@ -675,9 +713,10 @@ namespace std // Stage 1: extract and determine the conversion specifier. // Assuming leading zeros eliminated, thus the size of 32 for // integral types. - char __xtrc[32]= {'\0'}; + char __xtrc[32]; int __base; - _M_extract_int(__beg, __end, __io, __err, __xtrc, __base); + _M_extract_int(__beg, __end, __io, __err, __xtrc, + numeric_limits::digits10, __base); // Stage 2: convert and store results. char* __sanity; diff --git a/libstdc++-v3/src/locale.cc b/libstdc++-v3/src/locale.cc index c3572c40b15..2a16a3aeed2 100644 --- a/libstdc++-v3/src/locale.cc +++ b/libstdc++-v3/src/locale.cc @@ -74,7 +74,7 @@ namespace std // Definitions for static const data members of locale::id size_t locale::id::_S_highwater; // init'd to 0 by linker - const char __num_base::_S_atoms[] = "0123456789eEabcdfxABCDFX"; + const char __num_base::_S_atoms[] = "0123456789eEabcdfABCDF"; // Definitions for static const data members of locale::_Impl const locale::id* const diff --git a/libstdc++-v3/testsuite/27_io/istream_extractor_arith.cc b/libstdc++-v3/testsuite/27_io/istream_extractor_arith.cc index 0cb5ae0ed02..9a8537e82f8 100644 --- a/libstdc++-v3/testsuite/27_io/istream_extractor_arith.cc +++ b/libstdc++-v3/testsuite/27_io/istream_extractor_arith.cc @@ -513,6 +513,83 @@ bool test11() return test; } +// libstdc++/3720 +// excess input should not cause a core dump +template +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::digits10 + 1; + else + // This might do it, unsure. + digits_overflow = std::numeric_limits::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(true)); + VERIFY(test12_aux(true)); + VERIFY(test12_aux(true)); + VERIFY(test12_aux(false)); + VERIFY(test12_aux(false)); + VERIFY(test12_aux(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; + iss1 >> d; + VERIFY (d > 1246 && d < 1247); + + // 2 + // quick test for failbit on maximum length extraction. + int i; + int max_digits = numeric_limits::digits10; + string digits; + for (int j = 0; j < max_digits; ++j) + digits += '1'; + istringstream iss2(digits); + iss2 >> i; + VERIFY( iss2.good() ); + + digits += '1'; + i = 0; + iss2.str(digits); + iss2.clear(); + iss2 >> i; + VERIFY( i == 0 ); + VERIFY( iss2.fail() ); +} + int main() { test01(); @@ -526,6 +603,7 @@ int main() test10(); test11(); + test12(); return 0; } -- 2.30.2