libstdc++: Fix exception handling in std::ostream seek functions
N3168 added the requirement that the [ostream.seeks] functions create a sentry object. Nothing in the requirements of those functions says anything about catching exceptions and setting badbit. As well as not catching exceptions, this change results in another observable behaviour change. Previously seeking on a stream with eofbit set would work (as long as badbit and failbit weren't set). The construction of a sentry causes failbit to be set when eofbit is set, which causes the seek to fail. It is necessary to clear the eofbit before seeking now. libstdc++-v3/ChangeLog: * include/bits/ostream.tcc (sentry): Only set failbit if badbit is set, not if eofbit is set. (tellp, seekp, seekp): Create sentry object. Do not set badbit on exceptions. * testsuite/27_io/basic_ostream/seekp/char/exceptions_badbit_throw.cc: Adjust expected behaviour. * testsuite/27_io/basic_ostream/seekp/wchar_t/exceptions_badbit_throw.cc: Likewise. * testsuite/27_io/basic_ostream/tellp/char/exceptions_badbit_throw.cc: Likewise. * testsuite/27_io/basic_ostream/tellp/wchar_t/exceptions_badbit_throw.cc: Likewise. * testsuite/27_io/basic_ostream/seekp/char/n3168.cc: New test. * testsuite/27_io/basic_ostream/seekp/wchar_t/n3168.cc: New test. * testsuite/27_io/basic_ostream/tellp/char/n3168.cc: New test. * testsuite/27_io/basic_ostream/tellp/wchar_t/n3168.cc: New test.
This commit is contained in:
parent
7ab7fa1b51
commit
9b6c65c754
@ -53,7 +53,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
|
||||
if (__os.good())
|
||||
_M_ok = true;
|
||||
else
|
||||
else if (__os.bad())
|
||||
__os.setstate(ios_base::failbit);
|
||||
}
|
||||
|
||||
@ -236,19 +236,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
basic_ostream<_CharT, _Traits>::
|
||||
tellp()
|
||||
{
|
||||
sentry __cerb(*this);
|
||||
pos_type __ret = pos_type(-1);
|
||||
__try
|
||||
{
|
||||
if (!this->fail())
|
||||
__ret = this->rdbuf()->pubseekoff(0, ios_base::cur, ios_base::out);
|
||||
}
|
||||
__catch(__cxxabiv1::__forced_unwind&)
|
||||
{
|
||||
this->_M_setstate(ios_base::badbit);
|
||||
__throw_exception_again;
|
||||
}
|
||||
__catch(...)
|
||||
{ this->_M_setstate(ios_base::badbit); }
|
||||
if (!this->fail())
|
||||
__ret = this->rdbuf()->pubseekoff(0, ios_base::cur, ios_base::out);
|
||||
return __ret;
|
||||
}
|
||||
|
||||
@ -257,30 +248,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
basic_ostream<_CharT, _Traits>::
|
||||
seekp(pos_type __pos)
|
||||
{
|
||||
ios_base::iostate __err = ios_base::goodbit;
|
||||
__try
|
||||
sentry __cerb(*this);
|
||||
if (!this->fail())
|
||||
{
|
||||
if (!this->fail())
|
||||
{
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 136. seekp, seekg setting wrong streams?
|
||||
const pos_type __p = this->rdbuf()->pubseekpos(__pos,
|
||||
ios_base::out);
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 136. seekp, seekg setting wrong streams?
|
||||
const pos_type __p = this->rdbuf()->pubseekpos(__pos, ios_base::out);
|
||||
|
||||
// 129. Need error indication from seekp() and seekg()
|
||||
if (__p == pos_type(off_type(-1)))
|
||||
__err |= ios_base::failbit;
|
||||
}
|
||||
// 129. Need error indication from seekp() and seekg()
|
||||
if (__p == pos_type(off_type(-1)))
|
||||
this->setstate(ios_base::failbit);
|
||||
}
|
||||
__catch(__cxxabiv1::__forced_unwind&)
|
||||
{
|
||||
this->_M_setstate(ios_base::badbit);
|
||||
__throw_exception_again;
|
||||
}
|
||||
__catch(...)
|
||||
{ this->_M_setstate(ios_base::badbit); }
|
||||
if (__err)
|
||||
this->setstate(__err);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -289,30 +267,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
|
||||
basic_ostream<_CharT, _Traits>::
|
||||
seekp(off_type __off, ios_base::seekdir __dir)
|
||||
{
|
||||
ios_base::iostate __err = ios_base::goodbit;
|
||||
__try
|
||||
sentry __cerb(*this);
|
||||
if (!this->fail())
|
||||
{
|
||||
if (!this->fail())
|
||||
{
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 136. seekp, seekg setting wrong streams?
|
||||
const pos_type __p = this->rdbuf()->pubseekoff(__off, __dir,
|
||||
ios_base::out);
|
||||
// _GLIBCXX_RESOLVE_LIB_DEFECTS
|
||||
// 136. seekp, seekg setting wrong streams?
|
||||
const pos_type __p = this->rdbuf()->pubseekoff(__off, __dir,
|
||||
ios_base::out);
|
||||
|
||||
// 129. Need error indication from seekp() and seekg()
|
||||
if (__p == pos_type(off_type(-1)))
|
||||
__err |= ios_base::failbit;
|
||||
}
|
||||
// 129. Need error indication from seekp() and seekg()
|
||||
if (__p == pos_type(off_type(-1)))
|
||||
this->setstate(ios_base::failbit);
|
||||
}
|
||||
__catch(__cxxabiv1::__forced_unwind&)
|
||||
{
|
||||
this->_M_setstate(ios_base::badbit);
|
||||
__throw_exception_again;
|
||||
}
|
||||
__catch(...)
|
||||
{ this->_M_setstate(ios_base::badbit); }
|
||||
if (__err)
|
||||
this->setstate(__err);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,6 @@ void test01()
|
||||
|
||||
__gnu_test::fail_streambuf bib;
|
||||
ostream stream(&bib);
|
||||
stream.exceptions(ios_base::badbit);
|
||||
|
||||
ostream::pos_type pos = ostream::pos_type();
|
||||
|
||||
@ -37,14 +36,11 @@ void test01()
|
||||
stream.seekp(pos);
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
{
|
||||
// stream should set badbit and rethrow facet_error.
|
||||
VERIFY( stream.bad() );
|
||||
VERIFY( (stream.rdstate() & ios_base::failbit) == 0 );
|
||||
VERIFY( !stream.eof() );
|
||||
VERIFY( stream.good() );
|
||||
}
|
||||
catch (...)
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
@ -56,7 +52,6 @@ void test02()
|
||||
|
||||
__gnu_test::fail_streambuf bib;
|
||||
ostream stream(&bib);
|
||||
stream.exceptions(ios_base::badbit);
|
||||
|
||||
ostream::off_type off(5);
|
||||
|
||||
@ -65,14 +60,11 @@ void test02()
|
||||
stream.seekp(off, ios_base::cur);
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
{
|
||||
// stream should set badbit and rethrow facet_error.
|
||||
VERIFY( stream.bad() );
|
||||
VERIFY( (stream.rdstate() & ios_base::failbit) == 0 );
|
||||
VERIFY( !stream.eof() );
|
||||
VERIFY( stream.good() );
|
||||
}
|
||||
catch (...)
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
|
103
libstdc++-v3/testsuite/27_io/basic_ostream/seekp/char/n3168.cc
Normal file
103
libstdc++-v3/testsuite/27_io/basic_ostream/seekp/char/n3168.cc
Normal file
@ -0,0 +1,103 @@
|
||||
#include <ostream>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_io.h>
|
||||
|
||||
// C++11 27.7.3.5 basic_ostream seek members [ostream.seeks]
|
||||
|
||||
// Verify [ostream.seeks] functions use a sentry, as per N3168.
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
// Check that the sentry sets failbit when seeking on a bad stream.
|
||||
// The standard doesn't guarantee this, but it is true for libstdc++.
|
||||
|
||||
std::ostream os(0);
|
||||
VERIFY( os.rdstate() == std::ios_base::badbit );
|
||||
|
||||
std::ostream::pos_type pos = std::ostream::pos_type();
|
||||
os.seekp(pos);
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
|
||||
os.clear();
|
||||
std::ostream::off_type off(5);
|
||||
os.seekp(off, std::ios_base::cur);
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
|
||||
os.clear();
|
||||
os.exceptions(std::ios_base::failbit);
|
||||
|
||||
try
|
||||
{
|
||||
os.clear();
|
||||
os.seekp(pos);
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const std::ios_base::failure&)
|
||||
{
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
os.clear();
|
||||
os.seekp(off, std::ios_base::cur);
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const std::ios_base::failure&)
|
||||
{
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
// Check that the sentry flushes a tied stream when seeking.
|
||||
|
||||
{
|
||||
__gnu_test::sync_streambuf buf;
|
||||
std::ostream os(&buf);
|
||||
|
||||
__gnu_test::sync_streambuf buf_tie;
|
||||
std::ostream os_tie(&buf_tie);
|
||||
|
||||
os.tie(&os_tie);
|
||||
|
||||
std::ostream::pos_type pos = std::ostream::pos_type();
|
||||
os.seekp(pos);
|
||||
|
||||
VERIFY( ! buf.sync_called() );
|
||||
VERIFY( buf_tie.sync_called() );
|
||||
}
|
||||
|
||||
{
|
||||
__gnu_test::sync_streambuf buf;
|
||||
std::ostream os(&buf);
|
||||
|
||||
__gnu_test::sync_streambuf buf_tie;
|
||||
std::ostream os_tie(&buf_tie);
|
||||
|
||||
os.tie(&os_tie);
|
||||
|
||||
std::ostream::off_type off(0);
|
||||
os.seekp(off, std::ios_base::cur);
|
||||
|
||||
VERIFY( ! buf.sync_called() );
|
||||
VERIFY( buf_tie.sync_called() );
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
}
|
@ -28,7 +28,6 @@ void test01()
|
||||
|
||||
__gnu_test::fail_wstreambuf bib;
|
||||
wostream stream(&bib);
|
||||
stream.exceptions(ios_base::badbit);
|
||||
|
||||
wostream::pos_type pos = wostream::pos_type();
|
||||
|
||||
@ -37,14 +36,11 @@ void test01()
|
||||
stream.seekp(pos);
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
{
|
||||
// stream should set badbit and rethrow facet_error.
|
||||
VERIFY( stream.bad() );
|
||||
VERIFY( (stream.rdstate() & ios_base::failbit) == 0 );
|
||||
VERIFY( !stream.eof() );
|
||||
VERIFY( stream.good() );
|
||||
}
|
||||
catch (...)
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
@ -53,10 +49,9 @@ void test01()
|
||||
void test02()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
|
||||
__gnu_test::fail_wstreambuf bib;
|
||||
wostream stream(&bib);
|
||||
stream.exceptions(ios_base::badbit);
|
||||
|
||||
wostream::off_type off(5);
|
||||
|
||||
@ -65,14 +60,11 @@ void test02()
|
||||
stream.seekp(off, ios_base::cur);
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
{
|
||||
// stream should set badbit and rethrow facet_error.
|
||||
VERIFY( stream.bad() );
|
||||
VERIFY( (stream.rdstate() & ios_base::failbit) == 0 );
|
||||
VERIFY( !stream.eof() );
|
||||
VERIFY( stream.good() );
|
||||
}
|
||||
catch (...)
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
|
@ -0,0 +1,101 @@
|
||||
#include <ostream>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_io.h>
|
||||
|
||||
// C++11 27.7.3.5 basic_ostream seek members [ostream.seeks]
|
||||
|
||||
// Verify [ostream.seeks] functions use a sentry, as per N3168.
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
// Check that the sentry sets failbit when seeking on a bad stream.
|
||||
// The standard doesn't guarantee this, but it is true for libstdc++.
|
||||
|
||||
std::wostream os(0);
|
||||
VERIFY( os.rdstate() == std::ios_base::badbit );
|
||||
|
||||
std::wostream::pos_type pos = std::wostream::pos_type();
|
||||
os.seekp(pos);
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
|
||||
os.clear();
|
||||
std::wostream::off_type off(5);
|
||||
os.seekp(off, std::ios_base::cur);
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
|
||||
os.clear();
|
||||
os.exceptions(std::ios_base::failbit);
|
||||
|
||||
try
|
||||
{
|
||||
os.clear();
|
||||
os.seekp(pos);
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const std::ios_base::failure&)
|
||||
{
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
os.clear();
|
||||
os.seekp(off, std::ios_base::cur);
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const std::ios_base::failure&)
|
||||
{
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
// Check that the sentry flushes a tied stream when seeking.
|
||||
|
||||
{
|
||||
__gnu_test::sync_wstreambuf buf;
|
||||
std::wostream os(&buf);
|
||||
|
||||
__gnu_test::sync_wstreambuf buf_tie;
|
||||
std::wostream os_tie(&buf_tie);
|
||||
|
||||
os.tie(&os_tie);
|
||||
|
||||
std::wostream::pos_type pos = std::wostream::pos_type();
|
||||
os.seekp(pos);
|
||||
|
||||
VERIFY( buf_tie.sync_called() );
|
||||
}
|
||||
|
||||
{
|
||||
__gnu_test::sync_wstreambuf buf;
|
||||
std::wostream os(&buf);
|
||||
|
||||
__gnu_test::sync_wstreambuf buf_tie;
|
||||
std::wostream os_tie(&buf_tie);
|
||||
|
||||
os.tie(&os_tie);
|
||||
|
||||
std::wostream::off_type off(0);
|
||||
os.seekp(off, std::ios_base::cur);
|
||||
|
||||
VERIFY( buf_tie.sync_called() );
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
}
|
@ -28,21 +28,17 @@ void test01()
|
||||
{
|
||||
__gnu_test::fail_streambuf bib;
|
||||
ostream stream(&bib);
|
||||
stream.exceptions(ios_base::badbit);
|
||||
|
||||
try
|
||||
{
|
||||
stream.tellp();
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
{
|
||||
// stream should set badbit and rethrow facet_error.
|
||||
VERIFY( stream.bad() );
|
||||
VERIFY( (stream.rdstate() & ios_base::failbit) == 0 );
|
||||
VERIFY( !stream.eof() );
|
||||
VERIFY( stream.good() );
|
||||
}
|
||||
catch (...)
|
||||
catch (...)
|
||||
{
|
||||
VERIFY(false);
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
#include <ostream>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_io.h>
|
||||
|
||||
// C++11 27.7.3.5 basic_ostream seek members [ostream.seeks]
|
||||
|
||||
// Verify [ostream.seeks] functions use a sentry, as per N3168.
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
// Check that the sentry sets failbit when seeking on a bad stream.
|
||||
// The standard doesn't guarantee this, but it is true for libstdc++.
|
||||
|
||||
std::ostream os(0);
|
||||
VERIFY( os.rdstate() == std::ios_base::badbit );
|
||||
|
||||
os.tellp();
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
|
||||
os.clear();
|
||||
|
||||
os.exceptions(std::ios_base::failbit);
|
||||
|
||||
try
|
||||
{
|
||||
os.clear();
|
||||
os.tellp();
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const std::ios_base::failure&)
|
||||
{
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
// Check that the sentry flushes a tied stream when seeking.
|
||||
|
||||
__gnu_test::sync_streambuf buf;
|
||||
std::ostream os(&buf);
|
||||
|
||||
__gnu_test::sync_streambuf buf_tie;
|
||||
std::ostream os_tie(&buf_tie);
|
||||
|
||||
os.tie(&os_tie);
|
||||
|
||||
os.tellp();
|
||||
|
||||
VERIFY( ! buf.sync_called() );
|
||||
VERIFY( buf_tie.sync_called() );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
}
|
@ -28,21 +28,17 @@ void test01()
|
||||
{
|
||||
__gnu_test::fail_wstreambuf bib;
|
||||
wostream stream(&bib);
|
||||
stream.exceptions(ios_base::badbit);
|
||||
|
||||
try
|
||||
{
|
||||
stream.tellp();
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
catch (const __gnu_test::positioning_error&)
|
||||
{
|
||||
// stream should set badbit and rethrow facet_error.
|
||||
VERIFY( stream.bad() );
|
||||
VERIFY( (stream.rdstate() & ios_base::failbit) == 0 );
|
||||
VERIFY( !stream.eof() );
|
||||
VERIFY( stream.good() );
|
||||
}
|
||||
catch (...)
|
||||
catch (...)
|
||||
{
|
||||
VERIFY(false);
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
#include <ostream>
|
||||
#include <testsuite_hooks.h>
|
||||
#include <testsuite_io.h>
|
||||
|
||||
// C++11 27.7.3.5 basic_ostream seek members [ostream.seeks]
|
||||
|
||||
// Verify [ostream.seeks] functions use a sentry, as per N3168.
|
||||
|
||||
void
|
||||
test01()
|
||||
{
|
||||
// Check that the sentry sets failbit when seeking on a bad stream.
|
||||
// The standard doesn't guarantee this, but it is true for libstdc++.
|
||||
|
||||
std::wostream os(0);
|
||||
VERIFY( os.rdstate() == std::ios_base::badbit );
|
||||
|
||||
os.tellp();
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
|
||||
os.clear();
|
||||
|
||||
os.exceptions(std::ios_base::failbit);
|
||||
|
||||
try
|
||||
{
|
||||
os.clear();
|
||||
os.tellp();
|
||||
VERIFY( false );
|
||||
}
|
||||
catch (const std::ios_base::failure&)
|
||||
{
|
||||
VERIFY( os.rdstate() & std::ios_base::failbit );
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
VERIFY( false );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
test02()
|
||||
{
|
||||
// Check that the sentry flushes a tied stream when seeking.
|
||||
|
||||
__gnu_test::sync_wstreambuf buf;
|
||||
std::wostream os(&buf);
|
||||
|
||||
__gnu_test::sync_wstreambuf buf_tie;
|
||||
std::wostream os_tie(&buf_tie);
|
||||
|
||||
os.tie(&os_tie);
|
||||
|
||||
os.tellp();
|
||||
|
||||
VERIFY( ! buf.sync_called() );
|
||||
VERIFY( buf_tie.sync_called() );
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test01();
|
||||
test02();
|
||||
}
|
Loading…
Reference in New Issue
Block a user