This is the mail archive of the libstdc++@sources.redhat.com mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

2 bugs in basic_streambuf


Hi

The following (nonsensical) program crashes when compiled with
a recent snapshot of gcc:

#include <streambuf>
#include <iostream>
using namespace std;

class Weird : public streambuf
{
public:
    Weird()
        {
            char foo [10000];
            // No crash if this is removed
            setp(foo, foo + 10000);

            setp(buffer, buffer + 4);
        }
    ~Weird()
        {
            sync();
        }

    virtual int_type overflow(int_type n)
        {
            if (sync() != 0)
                return traits_type::eof();

            result += traits_type::to_char_type(n);

            return n;
        }

    virtual int sync()
        {
            result += std::string(pbase(), pptr());
            setp(buffer, buffer + 4);
            return 0;
        }

    char buffer [4];
    std::string result;
};

int main()
{
    std::string text1 = "abcdefghijklmn";

    Weird w;
    w.sputn(text1.c_str(), text1.length());
    w.pubsync();

    // Writes "abcdefghijklmn" if the first call to setp is removed
    cout << w.result << endl;
}


The cause of the crash is in basic_streambuf<>::setp (code snippet
from gcc-20001204):

      void 
      setp(char_type* __pbeg, char_type* __pend)
      { 
        _M_out_beg = _M_out_cur = __pbeg; 
        _M_out_end = __pend; 
        if (!(_M_mode & ios_base::out) && __pbeg && __pend)
          _M_mode = _M_mode | ios_base::out;
        // The output sequence is highly tied to _M_buf and
        // _M_buf_size in addition to the actual pointers into the
        // buffer. Because of this, (re)set _M_buf_size here, as
        // sputc/xsputn need _M_buf_size to be accurate. (The
        // corresponding input functions rely instead on _M_in_end.)

// _M_buf_size does not change when switching to a smaller
// buffer 
        _M_buf_size = max(_M_buf_size, static_cast<int_type>(__pend -
__pbeg));


      }


However, in sputc _M_buf_size is taken as the size of the buffer:
      if (_M_out_cur && _M_out_cur < _M_out_beg + _M_buf_size)

and also in xsputn:

              bool __testput = _M_out_cur < _M_out_beg + _M_buf_size;

...

                  if (_M_out_cur + __n - __ret <= _M_out_beg + _M_buf_size)
                    __len = __n - __ret;
                  else
                    __len = _M_out_beg + _M_buf_size - _M_out_cur;

Anyway, why not simply use _M_out_end instead of
_M_out_beg + _M_buf_size? (Or even make _M_out_beg, _M_out_cur etc.
private and use pbase(), pptr(), etc. everywhere?)



The other bug is in basic_streambuf<>::getloc:

      locale   
      getloc() const
      {
        if (_M_buf_locale_init)
          return _M_buf_locale; 
        else 

// This implies that changing the global locale will change the
// locales of existing streambufs (unless pubimbue has been called)
          return locale();
      } 

However there is also a member:

      const __ctype_type*	_M_buf_fctype;      

That is only updated in basic_streambuf<>::imbue, NOT when the global
locale changes. It seems that either getloc() is wrong, or that facets
can't be cached. (According to Stroustrup, 3rd edition, changing the
global locale should not affect existing streams, so getloc() is
probably wrong and _M_buf_locale_init unneccessary.)

Thanks
Petur

P.S. will <pfstream.h> come with gcc 3.0?


____________________________________________________________________
Get free email and a permanent address at http://www.netaddress.com/?N=1

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]