On 19/07/17 01:17 +0100, 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.

I spent a LOT of time checking the make check-performance results
before and after this patch (and with various other attempted fixes)
and any difference seemed to be noise.

        PR libstdc++/81395
        * include/bits/fstream.tcc (basic_filebuf::xsgetn): Don't set buffer
        pointers for write mode after reading.
        * testsuite/27_io/basic_filebuf/sgetn/char/81395.cc: New.

The new test needs this dg-require so it doesn't FAIL on target boards
with no file I/O, and the dg-do is redundant.

Committed to trunk.


commit e868d4e4a67faa9b889720b5fcdd10f5eb0f4fa8
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Wed Jul 19 01:19:20 2017 +0100

    Use dg-require-fileio in new test
    
    	* testsuite/27_io/basic_filebuf/sgetn/char/81395.cc: Add dg-require.

diff --git a/libstdc++-v3/testsuite/27_io/basic_filebuf/sgetn/char/81395.cc b/libstdc++-v3/testsuite/27_io/basic_filebuf/sgetn/char/81395.cc
index 4985628..ea8dbc1 100644
--- a/libstdc++-v3/testsuite/27_io/basic_filebuf/sgetn/char/81395.cc
+++ b/libstdc++-v3/testsuite/27_io/basic_filebuf/sgetn/char/81395.cc
@@ -15,7 +15,7 @@
 // with this library; see the file COPYING3.  If not see
 // <http://www.gnu.org/licenses/>.
 
-// { dg-do run }
+// { dg-require-fileio "" }
 
 // PR libstdc++/81395
 

Reply via email to