Mateusz Loskot :: hacking on, working out, living up

A bug in std::basic_istream from Visual C++

23 Jan 2008 | mloskot

Update: I submitted this problem to the Microsoft Connect and the Feedback ID is 323765

I believe I found a bug in Visual C++ implementation of the C++ Standard Library (AFAIR, it’s provided by Dinkumware,Ltd.). This is my first trove of that kind in Visual C++, thus I should exclaim Hurray! ;-). The C++ library discussed here is shipped with Visual C++ 8.0 compiler from the Visual Studio 2005 Professional.

Shortly, in the std::basic_istream class, implementation of input operator overloaded for unsigned long with Microsoft specific modifier __w64 consists of incorrect cast from reference to non-const to unsigned long, a nonreference type - rvalue.

Here is the buggy implementation copied (stripping unimportant lines) from the <istream> header, by default installed in c:filesvisual studio 8, near lines 309-326:

_Myt& operator>>(unsigned long __w64& _Val)
{ // extract an unsigned long
  ios_base::iostate _State = ios_base::goodbit;
  const sentry _Ok(*this);

  if (_Ok)
  {  // state okay, use facet to extract
     const _Nget& _Nget_fac = _USE(ios_base::getloc(), _Nget);

     _Nget_fac.get(_Iter(_Myios::rdbuf()), _Iter(0),
        *this, _State, (unsigned long)_Val);
  }

  _Myios::setstate(_State);
  return (*this);
}

In the code above, bug is in the line where std::num_get::get function is called. The 5th parameter is casted from reference to nonreference type:

(unsigned long)_Val

and, from the C++ Language Standard/3.10:

6 An expression wich holds a temporary object resulting from a cast to a nonreference type is an rvalue.

Next, the std::numget::get_ function call tries to bind the rvalue to reference to non-const type, according to its prototype:

// C++ Standard/22.2.2.1 - std::num_get class members
_InIt get(_InIt _First, _InIt _Last,
  ios_base& _Iosbase, ios_base::iostate& _State,
  unsigned long& _Val)

However, the C++ Standard/8.5.3 defines that

the reference shall be to a non-volatile const type.

Solution

The simplest solution is to fix the invalid cast, so the buggy line:

_Nget_fac.get(_Iter(_Myios::rdbuf()), _Iter(0),
  *this, _State, (unsigned long)_Val);

reads

_Nget_fac.get(_Iter(_Myios::rdbuf()), _Iter(0),
  *this, _State, (unsigned long&)_Val);

alternatively, it’s also possible to completely remove the cast of _Val object.

By the way, if you want to keep your C++ programs portable, it’s a good idea to disable Visual C++ language extensions using compiler option /Za.

Fork me on GitHub