aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Kosnik <bkoz@gcc.gnu.org>2001-12-07 02:58:36 +0000
committerBenjamin Kosnik <bkoz@gcc.gnu.org>2001-12-07 02:58:36 +0000
commit823b4f7daa4141d9986e8df7308f1d7fb19e03a8 (patch)
tree74795169d392cf89d1d1f0c8a0dd317675d7b8cf
parenta2b1e914592aebb8c495c7a7d5bc408d4cf368d3 (diff)
downloadgcc-823b4f7daa4141d9986e8df7308f1d7fb19e03a8.zip
gcc-823b4f7daa4141d9986e8df7308f1d7fb19e03a8.tar.gz
gcc-823b4f7daa4141d9986e8df7308f1d7fb19e03a8.tar.bz2
[multiple changes]
2001-12-06 Benjamin Kosnik <bkoz@redhat.com> 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 <pmartin@uklinux.net> * testsuite/27_io/istream_extractor_arith.cc (test12): Add tests for excess input digits. From-SVN: r47743
-rw-r--r--libstdc++-v3/ChangeLog22
-rw-r--r--libstdc++-v3/include/bits/locale_facets.h8
-rw-r--r--libstdc++-v3/include/bits/locale_facets.tcc205
-rw-r--r--libstdc++-v3/src/locale.cc2
-rw-r--r--libstdc++-v3/testsuite/27_io/istream_extractor_arith.cc78
5 files changed, 226 insertions, 89 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index b5dfa19..4348d33f 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,23 @@
+2001-12-06 Benjamin Kosnik <bkoz@redhat.com>
+
+ 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 <pmartin@uklinux.net>
+
+ * testsuite/27_io/istream_extractor_arith.cc (test12): Add
+ tests for excess input digits.
+
2001-12-06 Phil Edwards <pme@gcc.gnu.org>
* include/bits/std_bitset.h: Use GLIBCPP in multiple-inclusion guard.
@@ -42,7 +62,7 @@
2001-12-04 Paolo Carlini <pcarlini@unitus.it>
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 878f8b2..27bd5b1 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 95cbee5..363ff8b 100644
--- a/libstdc++-v3/include/bits/locale_facets.tcc
+++ b/libstdc++-v3/include/bits/locale_facets.tcc
@@ -35,6 +35,7 @@
#include <bits/std_cerrno.h>
#include <bits/std_clocale.h> // For localeconv
#include <bits/std_cstdlib.h> // For strof, strtold
+#include <bits/std_cmath.h> // For ceil
#include <bits/std_limits.h> // For numeric_limits
#include <bits/std_memory.h> // For auto_ptr
#include <bits/streambuf_iterator.h> // 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<ctype<_CharT> >(__loc);
const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__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<char>(__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<char>(__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<ctype<_CharT> >(__loc);
+ const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__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<ctype<_CharT> >(__loc);
- const numpunct<_CharT>& __np = use_facet<numpunct<_CharT> >(__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<int>(ceil(__max * log(10.0)
+ /log(static_cast<double>(__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<char>(__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<bool>::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<long>::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<unsigned short>::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<unsigned int>::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<unsigned long>::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<long long>::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<unsigned long long>::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<float>(strtod(__xtrc, &__sanity));
+ float __f = static_cast<float>(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<int_type>(__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<unsigned long>::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 c3572c4..2a16a3a 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 0cb5ae0..9a8537e 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<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;
+ 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.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;
}