Boost logo

Boost :

From: Lester Gong (ljmgong_at_[hidden])
Date: 2004-02-02 19:34:22


There is a bug in dynamic_bitset operator<<=().

Calling operator<<=() followed by operator>>=() may shift in non-zero
bits from the left.

For example, this sequence of statements ...

dynamic_bitset<> b(std::string("0110");
b <<= 1; // gives "1100"
b <<= 1; // gives "1000"
b <<= 1; // gives "0000"
b >>= 1; // gives "1000" !!
b >>= 1; // gives "1100" !!
b >>= 1; // gives "0110"

Seems that some stray bits are not cleared when shifted beyond the lhs
of the bitfield.

Attached files:

test_dynamic_bitset.cc Simple program that illustrates bug
test_dynamic_bitset.out Output from simple test program
dynamic_bitset.hpp.patch Patch that seems to fix the bug

bitset_test.hpp.patch
dyn_bitset_unit_tests2.cpp.patch Proposed changes to test programs
                                    that would catch this problem.

-Lester


#include <boost/dynamic_bitset.hpp>
#include <iostream>
#include <string>

using boost::dynamic_bitset;
using std::cout;
using std::endl;

int
main(int argv, char** argc)
{
  dynamic_bitset<> b(std::string("0110"));

  cout << "Original dynamic_bitset object:" << endl;
  cout << b << endl << endl;

  cout << "Shift left assignment (3 times):" << endl;
  b <<= 1;
  cout << b << endl;
  b <<= 1;
  cout << b << endl;
  b <<= 1;
  cout << b << endl << endl;

  cout << "Shift right assignment (3 times):" << endl;
  b >>= 1;
  cout << b << endl;
  b >>= 1;
  cout << b << endl;
  b >>= 1;
  cout << b << endl;

  return 0;
}

Original dynamic_bitset object:
0110

Shift left assignment (3 times):
1100
1000
0000

Shift right assignment (3 times):
1000
1100
0110


*** dynamic_bitset.hpp.orig Mon Feb 2 12:48:52 2004
--- dynamic_bitset.hpp Mon Feb 2 15:25:52 2004
***************
*** 670,676 ****
  
          // div blocks are zero filled at the less significant end
          std::fill(this->m_bits, this->m_bits+div, static_cast<block_type>(0));
!
  
      }
  
--- 670,676 ----
  
          // div blocks are zero filled at the less significant end
          std::fill(this->m_bits, this->m_bits+div, static_cast<block_type>(0));
! m_zero_unused_bits();
  
      }
  


*** bitset_test.hpp.orig Mon Feb 2 13:10:26 2004
--- bitset_test.hpp Mon Feb 2 15:21:34 2004
***************
*** 365,370 ****
--- 365,400 ----
          BOOST_CHECK(lhs[I] == prev[I + pos]);
    }
  
+ static void shift_left_assignment_followed_by_shift_right_assignment(const Bitset& b, std::size_t pos)
+ {
+ Bitset lhs(b);
+ Bitset prev(lhs);
+ lhs <<= pos;
+ lhs >>= pos;
+ // Check that zeros replace bits shifted off the end of the bitset.
+ std::size_t N = lhs.size();
+ for (std::size_t I = 0; I < N; ++I)
+ if (I < (N - pos))
+ BOOST_CHECK(lhs[I] == prev[I]);
+ else
+ BOOST_CHECK(lhs[I] == 0);
+ }
+
+ static void shift_right_assignment_followed_by_shift_left_assignment(const Bitset& b, std::size_t pos)
+ {
+ Bitset lhs(b);
+ Bitset prev(lhs);
+ lhs >>= pos;
+ lhs <<= pos;
+ // Check that zeros replace bits shifted off the end of the bitset.
+ std::size_t N = lhs.size();
+ for (std::size_t I = 0; I < N; ++I)
+ if (I >= pos)
+ BOOST_CHECK(lhs[I] == prev[I]);
+ else
+ BOOST_CHECK(lhs[I] == 0);
+ }
+
  
    static void set_all(const Bitset& b)
    {


*** dyn_bitset_unit_tests2.cpp.orig Mon Feb 2 13:10:44 2004
--- dyn_bitset_unit_tests2.cpp Mon Feb 2 15:28:26 2004
***************
*** 130,135 ****
--- 130,199 ----
      Tests::shift_right_assignment(b, pos);
    }
    //=====================================================================
+ // Test operator<<= followed by operator>>=
+ { // case pos == 0
+ std::size_t pos = 0;
+ boost::dynamic_bitset<Block> b(std::string("1010"));
+ Tests::shift_left_assignment_followed_by_shift_right_assignment(b, pos);
+ }
+ { // case pos == 1
+ std::size_t pos = 1;
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_left_assignment_followed_by_shift_right_assignment(b, pos);
+ }
+ { // case pos == <half of Block>
+ std::size_t pos = (sizeof(Block) * CHAR_BIT) / 2;
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_left_assignment_followed_by_shift_right_assignment(b, pos);
+ }
+ { // case pos == <full Block>
+ std::size_t pos = sizeof(Block) * CHAR_BIT;
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_left_assignment_followed_by_shift_right_assignment(b, pos);
+ }
+ { // case pos == size()/2
+ std::size_t pos = long_string.size() / 2;
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_left_assignment_followed_by_shift_right_assignment(b, pos);
+ }
+ { // case pos >= n
+ std::size_t pos = long_string.size();
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_left_assignment_followed_by_shift_right_assignment(b, pos);
+ }
+ //=====================================================================
+ // Test operator>>= followed by operator<<=
+ { // case pos == 0
+ std::size_t pos = 0;
+ boost::dynamic_bitset<Block> b(std::string("1010"));
+ Tests::shift_right_assignment_followed_by_shift_left_assignment(b, pos);
+ }
+ { // case pos == 1
+ std::size_t pos = 1;
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_right_assignment_followed_by_shift_left_assignment(b, pos);
+ }
+ { // case pos == <half of Block>
+ std::size_t pos = (sizeof(Block) * CHAR_BIT) / 2;
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_right_assignment_followed_by_shift_left_assignment(b, pos);
+ }
+ { // case pos == <full Block>
+ std::size_t pos = sizeof(Block) * CHAR_BIT;
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_right_assignment_followed_by_shift_left_assignment(b, pos);
+ }
+ { // case pos == size()/2
+ std::size_t pos = long_string.size() / 2;
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_right_assignment_followed_by_shift_left_assignment(b, pos);
+ }
+ { // case pos >= n
+ std::size_t pos = long_string.size();
+ boost::dynamic_bitset<Block> b(long_string);
+ Tests::shift_right_assignment_followed_by_shift_left_assignment(b, pos);
+ }
+ //=====================================================================
    // test b.set()
    {
      boost::dynamic_bitset<Block> b;


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk