https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81395
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|UNCONFIRMED |NEW
Last reconfirmed| |2017-07-11
Ever confirmed|0 |1
--- Comment #1 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Jonathan Wakely from comment #0)
> The problem is that the write calls overflow which starts with:
Correction: the destructor calls overflow in this testcase. In the original
testcase from a customer there was a write of BUFSIZ, which triggered overflow
after filling the put area. A more direct way to reproduce it is by changing
the final s << 'B'; to:
s.write("B", 1);
s.flush();
I can prevent the recursion with either:
@@ -515,6 +515,7 @@
if (_M_reading)
{
_M_destroy_pback();
+ _M_reading = false;
const int __gptr_off = _M_get_ext_pos(_M_state_last);
if (_M_seek(__gptr_off, ios_base::cur, _M_state_last)
== pos_type(off_type(-1)))
or:
@@ -920,7 +925,7 @@
{
// Part one: update the output sequence.
bool __testvalid = true;
- if (this->pbase() < this->pptr())
+ if (this->pbase() < this->pptr() && __builtin_expect(!_M_reading, 1))
{
const int_type __tmp = this->overflow();
if (traits_type::eq_int_type(__tmp, traits_type::eof()))
But why are we getting into this state anyway? We have a non-empty output
sequence when _M_reading is true, meaning we're in the middle of an uncommitted
read.
At the end of basic_filebuf::xsgetn after the read we do:
if (__n == 0)
{
_M_set_buffer(0);
_M_reading = true;
}
And _M_set_buffer(0) on a bidirectional filebuf sets up the put area:
if (__testout && __off == 0 && _M_buf_size > 1 )
this->setp(_M_buf, _M_buf + _M_buf_size - 1);
else
this->setp(0, 0);
This means the next write inserts straight into the put area, and then the next
overflow() finds that _M_reading is true but there is also a pending output
sequence.