Hi,
On 19/07/2017 02:17, Jonathan Wakely wrote:
This fixes a crash that happens in std::filebuf when a large read
consumes the entire get area and is followed by a write, which is then
synced to the file by a call to overflow.
The problem is that xsgetn calls _M_set_buffer(0) after reading from
the file (i.e. when in 'read' mode). As the comments on _M_set_buffer
say, an argument of 0 is used for 'write' mode. This causes the
filebuf to have an active put area while in 'read' mode, so that the
next write inserts straight into that put area, rather than performing
the required seek to leave 'read' mode.
The next overflow then tries to leave 'read' mode by doing a seek, but
that then tries to flush the non-empty put area by calling overflow,
which goes into a loop until we overflow the stack.
The solution is to simply remove the call to _M_set_buffer(0). It's
not needed because the buffers are already set up appropriately after
xsgetn has read from the file: there's no active putback, no put area,
and setg(eback(), egptr(), egptr()) has been called so there's nothing
available in the get area. All we need to do is set _M_reading = true
so that a following write knows it needs to perform a seek.
The new testcase passes with GCC 4.5, so this is technically a
regression. However, I have a more demanding test that fails even with
GCC 4.5, so I don't think mixing reads and writes without intervening
seeks was ever working completely. I hope it is now.
Excellent work on this, thanks Jon. Time permitting, I mean to
investigate a bit more your last interesting observation: I suspected
that the crazy _M_set_buffer (0) call or the idea itself of calling
_M_set_buffer in this case, was coming somehow from previous
incarnations of the buffer, which was already "suboptimal" in this
respect and didn't make progress... until today ;)
Paolo.