diff options
author | David Krauss <potswa@mac.com> | 2010-09-22 19:40:43 +0000 |
---|---|---|
committer | Paolo Carlini <paolo@gcc.gnu.org> | 2010-09-22 19:40:43 +0000 |
commit | 3531cf5ef365860700c5e89483f3a86ac969c6a4 (patch) | |
tree | a04325d2591098556af14addef9debb056684968 /libstdc++-v3/include | |
parent | 5d64ee190c8875dec5f15c0287a425a1e62041a9 (diff) | |
download | gcc-3531cf5ef365860700c5e89483f3a86ac969c6a4.zip gcc-3531cf5ef365860700c5e89483f3a86ac969c6a4.tar.gz gcc-3531cf5ef365860700c5e89483f3a86ac969c6a4.tar.bz2 |
re PR libstdc++/45628 (std::fstream::tellg invalidates I/O buffer)
2010-09-22 David Krauss <potswa@mac.com>
PR libstdc++/45628
* include/bits/fstream.tcc (basic_filebuf::underflow): Add state
transition to avoid modality requiring seekoff(0,ios::cur).
(basic_filebuf::pbackfail): Likewise.
(basic_filebuf::overflow): Likewise.
(basic_filebuf::_M_seek): Avoid minor unnecessary conversion.
(basic_filebuf::seekoff): Remove code to _M_get_ext_pos; make
(0, ios::cur) a special case preserving buffer contents.
(basic_filebuf::_M_get_ext_pos): New function to obtain status
about codecvt extern_t buffer for overflow and seekoff.
* include/std/fstream (basic_filebuf::_M_get_ext_pos): Likewise.
* config/abi/pre/gnu.ver: Export new symbols.
* testsuite/27_io/basic_filebuf/seekoff/char/45628-1.cc: New,
verifies that seekoff(0, ios::cur) preserves buffers.
* testsuite/27_io/basic_filebuf/seekoff/char/45628-2.cc: Likewise.
for codecvt case. More lenient as it may still flush put area.
* testsuite/27_io/basic_filebuf/seekoff/char/4.cc: Modify to
check that seekoff is not required between read and write.
* testsuite/27_io/basic_filebuf/seekoff/wchar_t/4.cc: Likewise.
* testsuite/27_io/basic_filebuf/sync/wchar_t/1.cc: Remove.
* testsuite/27_io/basic_filebuf/sync/wchar_t/1.cc: Likewise.
* testsuite/util/testsuite_character.h (codecvt::do_length): Comply
with 22.2.1.5.2/10 "Returns ... the LARGEST value in the range..."
From-SVN: r164529
Diffstat (limited to 'libstdc++-v3/include')
-rw-r--r-- | libstdc++-v3/include/bits/fstream.tcc | 100 | ||||
-rw-r--r-- | libstdc++-v3/include/std/fstream | 5 |
2 files changed, 80 insertions, 25 deletions
diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc index c498f48..2f661eb 100644 --- a/libstdc++-v3/include/bits/fstream.tcc +++ b/libstdc++-v3/include/bits/fstream.tcc @@ -1,7 +1,7 @@ // File based streams -*- C++ -*- // Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, -// 2007, 2008, 2009 +// 2007, 2008, 2009, 2010 // Free Software Foundation, Inc. // // This file is part of the GNU ISO C++ Library. This library is free @@ -205,8 +205,16 @@ _GLIBCXX_BEGIN_NAMESPACE(std) { int_type __ret = traits_type::eof(); const bool __testin = _M_mode & ios_base::in; - if (__testin && !_M_writing) + if (__testin) { + if (_M_writing) + { + __ret = overflow(); + if (__ret == traits_type::eof()) + return __ret; + _M_set_buffer(-1); + _M_writing = false; + } // Check for pback madness, and if so switch back to the // normal buffers and jet outta here before expensive // fileops happen... @@ -357,8 +365,16 @@ _GLIBCXX_BEGIN_NAMESPACE(std) { int_type __ret = traits_type::eof(); const bool __testin = _M_mode & ios_base::in; - if (__testin && !_M_writing) + if (__testin) { + if (_M_writing) + { + __ret = overflow(); + if (__ret == traits_type::eof()) + return __ret; + _M_set_buffer(-1); + _M_writing = false; + } // Remember whether the pback buffer is active, otherwise below // we may try to store in it a second char (libstdc++/9761). const bool __testpb = _M_pback_init; @@ -410,8 +426,16 @@ _GLIBCXX_BEGIN_NAMESPACE(std) int_type __ret = traits_type::eof(); const bool __testeof = traits_type::eq_int_type(__c, __ret); const bool __testout = _M_mode & ios_base::out; - if (__testout && !_M_reading) + if (__testout) { + if (_M_reading) + { + _M_destroy_pback(); + 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))) + return __ret; + } if (this->pbase() < this->pptr()) { // If appropriate, append the overflow char. @@ -691,12 +715,20 @@ _GLIBCXX_BEGIN_NAMESPACE(std) if (__width < 0) __width = 0; - pos_type __ret = pos_type(off_type(-1)); + pos_type __ret = pos_type(off_type(-1)); const bool __testfail = __off != 0 && __width <= 0; if (this->is_open() && !__testfail) { + // tellg and tellp queries do not affect any state, unless + // ! always_noconv and the put sequence is not empty. + // In that case, determining the position requires converting the + // put sequence. That doesn't use ext_buf, so requires a flush. + bool __no_movement = __way == ios_base::cur && __off == 0 + && (!_M_writing || _M_codecvt->always_noconv()); + // Ditch any pback buffers to avoid confusion. - _M_destroy_pback(); + if (!__no_movement) + _M_destroy_pback(); // Correct state at destination. Note that this is the correct // state for the current position during output, because @@ -707,24 +739,23 @@ _GLIBCXX_BEGIN_NAMESPACE(std) off_type __computed_off = __off * __width; if (_M_reading && __way == ios_base::cur) { - if (_M_codecvt->always_noconv()) - __computed_off += this->gptr() - this->egptr(); - else + __state = _M_state_last; + __computed_off += _M_get_ext_pos(__state); + } + if (!__no_movement) + __ret = _M_seek(__computed_off, __way, __state); + else + { + if (_M_writing) + __computed_off = this->pptr() - this->pbase(); + + off_type __file_off = _M_file.seekoff(0, ios_base::cur); + if (__file_off != off_type(-1)) { - // Calculate offset from _M_ext_buf that corresponds - // to gptr(). Note: uses _M_state_last, which - // corresponds to eback(). - const int __gptr_off = - _M_codecvt->length(_M_state_last, _M_ext_buf, _M_ext_next, - this->gptr() - this->eback()); - __computed_off += _M_ext_buf + __gptr_off - _M_ext_end; - - // _M_state_last is modified by codecvt::length() so - // it now corresponds to gptr(). - __state = _M_state_last; + __ret = __file_off + __computed_off; + __ret.state(__state); } } - __ret = _M_seek(__computed_off, __way, __state); } return __ret; } @@ -756,21 +787,42 @@ _GLIBCXX_BEGIN_NAMESPACE(std) pos_type __ret = pos_type(off_type(-1)); if (_M_terminate_output()) { - // Returns pos_type(off_type(-1)) in case of failure. - __ret = pos_type(_M_file.seekoff(__off, __way)); - if (__ret != pos_type(off_type(-1))) + off_type __file_off = _M_file.seekoff(__off, __way); + if (__file_off != off_type(-1)) { _M_reading = false; _M_writing = false; _M_ext_next = _M_ext_end = _M_ext_buf; _M_set_buffer(-1); _M_state_cur = __state; + __ret = __file_off; __ret.state(_M_state_cur); } } return __ret; } + // Returns the distance from the end of the ext buffer to the point + // corresponding to gptr(). This is a negative value. Updates __state + // from eback() correspondence to gptr(). + template<typename _CharT, typename _Traits> + int basic_filebuf<_CharT, _Traits>:: + _M_get_ext_pos(__state_type& __state) + { + if (_M_codecvt->always_noconv()) + return this->gptr() - this->egptr(); + else + { + // Calculate offset from _M_ext_buf that corresponds to + // gptr(). Precondition: __state == _M_state_last, which + // corresponds to eback(). + const int __gptr_off = + _M_codecvt->length(__state, _M_ext_buf, _M_ext_next, + this->gptr() - this->eback()); + return _M_ext_buf + __gptr_off - _M_ext_end; + } + } + template<typename _CharT, typename _Traits> bool basic_filebuf<_CharT, _Traits>:: diff --git a/libstdc++-v3/include/std/fstream b/libstdc++-v3/include/std/fstream index 00690be..0ffd33d 100644 --- a/libstdc++-v3/include/std/fstream +++ b/libstdc++-v3/include/std/fstream @@ -351,9 +351,12 @@ _GLIBCXX_BEGIN_NAMESPACE(std) seekpos(pos_type __pos, ios_base::openmode __mode = ios_base::in | ios_base::out); - // Common code for seekoff and seekpos + // Common code for seekoff, seekpos, and overflow pos_type _M_seek(off_type __off, ios_base::seekdir __way, __state_type __state); + + int + _M_get_ext_pos(__state_type &__state); virtual int sync(); |