From 3bbfb3d91dd6137f419c9d85ce7c75bb96e860b0 Mon Sep 17 00:00:00 2001 From: Phil Edwards Date: Fri, 27 Dec 2002 00:03:17 +0000 Subject: [PATCH] std_bitset.h (_Base_bitset::_M_do_left_shift, [...]): Expect a non-zero shift. 2002-12-26 Phil Edwards * include/std/std_bitset.h (_Base_bitset::_M_do_left_shift, _Base_bitset::_M_do_right_shift): Expect a non-zero shift. (bitset::operator<<=, bitset::operator>>=): When shifting more bits than are in the bitset, zero memory rather than segfault. (operator>>(basic_istream,bitset): Only call setstate once, after all work has been done. * testsuite/23_containers/bitset_members.cc (test03): New test. * testsuite/23_containers/bitset_shift.cc (test02): New test. From-SVN: r60533 --- libstdc++-v3/ChangeLog | 12 ++++++ libstdc++-v3/include/std/std_bitset.h | 43 +++++++++++++------ .../testsuite/23_containers/bitset_members.cc | 18 ++++++++ .../testsuite/23_containers/bitset_shift.cc | 16 +++++++ 4 files changed, 75 insertions(+), 14 deletions(-) diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index d6cd0041f88..f613267f932 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,15 @@ +2002-12-26 Phil Edwards + + * include/std/std_bitset.h (_Base_bitset::_M_do_left_shift, + _Base_bitset::_M_do_right_shift): Expect a non-zero shift. + (bitset::operator<<=, bitset::operator>>=): When shifting more bits + than are in the bitset, zero memory rather than segfault. + (operator>>(basic_istream,bitset): Only call setstate once, after + all work has been done. + + * testsuite/23_containers/bitset_members.cc (test03): New test. + * testsuite/23_containers/bitset_shift.cc (test02): New test. + 2002-12-26 Phil Edwards * libsupc++/vterminate.cc (writestr): Use __builtin_strlen. diff --git a/libstdc++-v3/include/std/std_bitset.h b/libstdc++-v3/include/std/std_bitset.h index f2fde3111d1..83693f5e0b2 100644 --- a/libstdc++-v3/include/std/std_bitset.h +++ b/libstdc++-v3/include/std/std_bitset.h @@ -219,7 +219,7 @@ namespace std void _Base_bitset<_Nw>::_M_do_left_shift(size_t __shift) { - if (__shift != 0) + if (__builtin_expect(__shift != 0, 1)) { const size_t __wshift = __shift / _GLIBCPP_BITSET_BITS_PER_WORD; const size_t __offset = __shift % _GLIBCPP_BITSET_BITS_PER_WORD; @@ -244,7 +244,7 @@ namespace std void _Base_bitset<_Nw>::_M_do_right_shift(size_t __shift) { - if (__shift != 0) + if (__builtin_expect(__shift != 0, 1)) { const size_t __wshift = __shift / _GLIBCPP_BITSET_BITS_PER_WORD; const size_t __offset = __shift % _GLIBCPP_BITSET_BITS_PER_WORD; @@ -581,9 +581,11 @@ namespace std * The template argument, @a _Nb, may be any non-negative number of type * size_t. * - * A %bitset of size N has N % (sizeof(unsigned long) * CHAR_BIT) unused - * bits. (They are the high-order bits in the highest word.) It is - * a class invariant that those unused bits are always zero. + * A %bitset of size N uses U bits, where + * U = (N % (sizeof(unsigned long) * CHAR_BIT)). + * Thus, N - U bits are unused. (They are the high-order bits in the + * highest word.) It is a class invariant that those unused bits are + * always zero. * * If you think of %bitset as "a simple array of bits," be aware that * your mental picture is reversed: a %bitset behaves the same way as @@ -805,16 +807,26 @@ namespace std bitset<_Nb>& operator<<=(size_t __pos) { - this->_M_do_left_shift(__pos); - this->_M_do_sanitize(); + if (__builtin_expect(__pos < _Nb, 1)) + { + this->_M_do_left_shift(__pos); + this->_M_do_sanitize(); + } + else + this->_M_do_reset(); return *this; } bitset<_Nb>& operator>>=(size_t __pos) { - this->_M_do_right_shift(__pos); - this->_M_do_sanitize(); + if (__builtin_expect(__pos < _Nb, 1)) + { + this->_M_do_right_shift(__pos); + this->_M_do_sanitize(); + } + else + this->_M_do_reset(); return *this; } //@} @@ -1183,6 +1195,7 @@ namespace std typename basic_istream<_CharT, _Traits>::sentry __sentry(__is); if (__sentry) { + ios_base::iostate __state = ios_base::goodbit; basic_streambuf<_CharT, _Traits>* __buf = __is.rdbuf(); for (size_t __i = 0; __i < _Nb; ++__i) { @@ -1191,7 +1204,7 @@ namespace std typename _Traits::int_type __c1 = __buf->sbumpc(); if (_Traits::eq_int_type(__c1, __eof)) { - __is.setstate(ios_base::eofbit); + __state |= ios_base::eofbit; break; } else @@ -1201,19 +1214,21 @@ namespace std if (__c == '0' || __c == '1') __tmp.push_back(__c); - else if (_Traits::eq_int_type(__buf->sputbackc(__c2), - __eof)) + else if (_Traits::eq_int_type(__buf->sputbackc(__c2), __eof)) { - __is.setstate(ios_base::failbit); + __state |= ios_base::failbit; break; } } } if (__tmp.empty() && !_Nb) - __is.setstate(ios_base::failbit); + __state |= ios_base::failbit; else __x._M_copy_from_string(__tmp, static_cast(0), _Nb); + + if (__state != ios_base::goodbit) + __is.setstate(__state); // may throw an exception } return __is; diff --git a/libstdc++-v3/testsuite/23_containers/bitset_members.cc b/libstdc++-v3/testsuite/23_containers/bitset_members.cc index 30e0ab6e063..054018df662 100644 --- a/libstdc++-v3/testsuite/23_containers/bitset_members.cc +++ b/libstdc++-v3/testsuite/23_containers/bitset_members.cc @@ -22,6 +22,7 @@ #include #include +#include #include void @@ -52,9 +53,26 @@ void test02() bs.count(); } +void test03() +{ + std::bitset<5> b; + std::stringstream ss ("101"); + + ss.exceptions(std::ios_base::eofbit); + + try + { + ss >> b; + } + catch (std::exception&) {} + + VERIFY( b.to_ulong() == 5 ); +} + int main() { test01(); test02(); + test03(); return 0; } diff --git a/libstdc++-v3/testsuite/23_containers/bitset_shift.cc b/libstdc++-v3/testsuite/23_containers/bitset_shift.cc index 35531bf5b4c..01fdd2fbc4b 100644 --- a/libstdc++-v3/testsuite/23_containers/bitset_shift.cc +++ b/libstdc++-v3/testsuite/23_containers/bitset_shift.cc @@ -106,9 +106,25 @@ test01() { return test; } +bool +test02() +{ + bool test = true; + + std::bitset<66> b; + b <<= 400; + VERIFY( b.count() == 0 ); + +#ifdef DEBUG_ASSERT + assert(test); +#endif + return test; +} + int main() { test01(); + test02(); return 0; } -- 2.30.2