This is the mail archive of the
libstdc++@sources.redhat.com
mailing list for the libstdc++ project.
2 bugs in basic_streambuf
- To: libstdc++ at gcc dot gnu dot org
- Subject: 2 bugs in basic_streambuf
- From: PETUR R <peturr at usa dot net>
- Date: 9 Dec 00 19:48:27 GMT
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