From f0d114aa8331ae8228ee32a4ffa9efd3953d8bf5 Mon Sep 17 00:00:00 2001 From: grcm10 Date: Wed, 7 Feb 2024 20:48:39 +0900 Subject: [PATCH 1/2] Fix rethrowing the caught exception from streambuf --- stl/inc/ostream | 6 ++-- .../GH_001858_iostream_exception/test.cpp | 33 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/stl/inc/ostream b/stl/inc/ostream index df2dd3f6b46..b2d718ef90b 100644 --- a/stl/inc/ostream +++ b/stl/inc/ostream @@ -493,8 +493,10 @@ public: _TRY_BEGIN _Meta = _Traits::eq_int_type(_Traits::eof(), _Meta) ? _Strbuf->sgetc() : _Strbuf->snextc(); _CATCH_ALL - _Myios::setstate(ios_base::failbit); - _RERAISE; + // N4971 [ostream.inserters]/8-9: "...If an exception was thrown + // while extracting a character, the function sets failbit in the error state, + // and if failbit is set in exceptions() the caught exception is rethrown." + _Myios::setstate(ios_base::failbit, (_Myios::exceptions() == ios_base::failbit)); _CATCH_END if (_Traits::eq_int_type(_Traits::eof(), _Meta)) { diff --git a/tests/std/tests/GH_001858_iostream_exception/test.cpp b/tests/std/tests/GH_001858_iostream_exception/test.cpp index 9b9bc47ef29..257980fb310 100644 --- a/tests/std/tests/GH_001858_iostream_exception/test.cpp +++ b/tests/std/tests/GH_001858_iostream_exception/test.cpp @@ -36,6 +36,8 @@ struct test_exception {}; template class throwing_buffer : public basic_streambuf { public: + using typename basic_streambuf::int_type; + streampos seekoff(streamoff, ios_base::seekdir, ios_base::openmode = ios_base::in | ios_base::out) override { throw test_exception{}; } @@ -48,6 +50,10 @@ class throwing_buffer : public basic_streambuf { throw test_exception{}; } + int_type underflow() override { + throw test_exception{}; + } + basic_streambuf* to_buf() { return this; } @@ -229,6 +235,33 @@ void test_ostream_exceptions() { // Expected case } } + + { // operator<< with exceptions + basic_ostream os(buffer.to_buf()); + os.exceptions(ios_base::goodbit); + + try { + os << &buffer; + } catch (const ios_base::failure&) { + assert(false); + } catch (const test_exception&) { + assert(false); + } + } + + { // operator<< rethrow the caught exception if failbit is set in exceptions() + basic_ostream os(buffer.to_buf()); + os.exceptions(ios_base::failbit); + + try { + os << &buffer; + assert(false); + } catch (const ios_base::failure&) { + assert(false); + } catch (const test_exception&) { + // Expected case + } + } } // Also test strengthened and mandatory exception specifications. From 8e681168baf027fa1c2c4fc31367f93da510d116 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 7 Feb 2024 12:55:28 -0800 Subject: [PATCH 2/2] Code review feedback. --- stl/inc/ostream | 4 ++-- tests/std/tests/GH_001858_iostream_exception/test.cpp | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/stl/inc/ostream b/stl/inc/ostream index b2d718ef90b..970cd37b731 100644 --- a/stl/inc/ostream +++ b/stl/inc/ostream @@ -493,10 +493,10 @@ public: _TRY_BEGIN _Meta = _Traits::eq_int_type(_Traits::eof(), _Meta) ? _Strbuf->sgetc() : _Strbuf->snextc(); _CATCH_ALL - // N4971 [ostream.inserters]/8-9: "...If an exception was thrown + // N4971 [ostream.inserters]/9: "If an exception was thrown // while extracting a character, the function sets failbit in the error state, // and if failbit is set in exceptions() the caught exception is rethrown." - _Myios::setstate(ios_base::failbit, (_Myios::exceptions() == ios_base::failbit)); + _Myios::setstate(ios_base::failbit, _Myios::exceptions() == ios_base::failbit); _CATCH_END if (_Traits::eq_int_type(_Traits::eof(), _Meta)) { diff --git a/tests/std/tests/GH_001858_iostream_exception/test.cpp b/tests/std/tests/GH_001858_iostream_exception/test.cpp index 257980fb310..5991d5e131d 100644 --- a/tests/std/tests/GH_001858_iostream_exception/test.cpp +++ b/tests/std/tests/GH_001858_iostream_exception/test.cpp @@ -236,9 +236,8 @@ void test_ostream_exceptions() { } } - { // operator<< with exceptions + { // operator<< (testing GH-4322 ": Exception from streambuf should be caught and not rethrown") basic_ostream os(buffer.to_buf()); - os.exceptions(ios_base::goodbit); try { os << &buffer; @@ -249,7 +248,7 @@ void test_ostream_exceptions() { } } - { // operator<< rethrow the caught exception if failbit is set in exceptions() + { // operator<< rethrows the caught exception if failbit is set in exceptions() basic_ostream os(buffer.to_buf()); os.exceptions(ios_base::failbit);