Skip to content

Commit

Permalink
Properly catch exceptions in {i|o}stream
Browse files Browse the repository at this point in the history
  • Loading branch information
miscco committed Jul 1, 2021
1 parent e745bad commit 3c59e25
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 16 deletions.
28 changes: 18 additions & 10 deletions stl/inc/istream
Original file line number Diff line number Diff line change
Expand Up @@ -619,14 +619,12 @@ public:
return -1;
}

bool _Sync_failed = true; // sync fails if an exception is thrown
_TRY_IO_BEGIN
_Sync_failed = _Rdbuf->pubsync() == -1;
_CATCH_IO_END
if (_Sync_failed) {
if (_Rdbuf->pubsync() == -1) {
_Myios::setstate(ios_base::badbit);
return -1;
}
_CATCH_IO_END

return 0;
}
Expand All @@ -637,8 +635,12 @@ public:
_Myios::clear(_Oldstate & ~ios_base::eofbit);
const sentry _Ok(*this, true);

if (!this->fail() && static_cast<off_type>(_Myios::rdbuf()->pubseekpos(_Pos, ios_base::in)) == -1) {
_Myios::setstate(_State | ios_base::failbit);
if (!this->fail()) {
_TRY_IO_BEGIN
if (static_cast<off_type>(_Myios::rdbuf()->pubseekpos(_Pos, ios_base::in)) == -1) {
_Myios::setstate(_State | ios_base::failbit);
}
_CATCH_IO_END
}

return *this;
Expand All @@ -651,8 +653,12 @@ public:
_Myios::clear(_Oldstate & ~ios_base::eofbit);
const sentry _Ok(*this, true);

if (!this->fail() && static_cast<off_type>(_Myios::rdbuf()->pubseekoff(_Off, _Way, ios_base::in)) == -1) {
_Myios::setstate(_State | ios_base::failbit);
if (!this->fail()) {
_TRY_IO_BEGIN
if (static_cast<off_type>(_Myios::rdbuf()->pubseekoff(_Off, _Way, ios_base::in)) == -1) {
_Myios::setstate(_State | ios_base::failbit);
}
_CATCH_IO_END
}

return *this;
Expand All @@ -662,10 +668,12 @@ public:
const sentry _Ok(*this, true);

if (!this->fail()) {
_TRY_IO_BEGIN
return _Myios::rdbuf()->pubseekoff(0, ios_base::cur, ios_base::in);
} else {
return pos_type(-1);
_CATCH_IO_END
}

return pos_type(-1);
}

private:
Expand Down
24 changes: 18 additions & 6 deletions stl/inc/ostream
Original file line number Diff line number Diff line change
Expand Up @@ -547,18 +547,24 @@ public:
if (_Rdbuf) { // buffer exists, flush it
const sentry _Ok(*this);

_TRY_IO_BEGIN
if (_Ok && _Rdbuf->pubsync() == -1) {
_Myios::setstate(ios_base::badbit); // sync failed
}
_CATCH_IO_END
}
return *this;
}

basic_ostream& __CLR_OR_THIS_CALL seekp(pos_type _Pos) { // set output stream position to _Pos
const sentry _Ok(*this);

if (!this->fail() && static_cast<off_type>(_Myios::rdbuf()->pubseekpos(_Pos, ios_base::out)) == -1) {
_Myios::setstate(ios_base::failbit);
if (!this->fail()) {
_TRY_IO_BEGIN
if (static_cast<off_type>(_Myios::rdbuf()->pubseekpos(_Pos, ios_base::out)) == -1) {
_Myios::setstate(ios_base::failbit);
}
_CATCH_IO_END
}

return *this;
Expand All @@ -568,8 +574,12 @@ public:
off_type _Off, ios_base::seekdir _Way) { // change output stream position by _Off, according to _Way
const sentry _Ok(*this);

if (!this->fail() && static_cast<off_type>(_Myios::rdbuf()->pubseekoff(_Off, _Way, ios_base::out)) == -1) {
_Myios::setstate(ios_base::failbit);
if (!this->fail()) {
_TRY_IO_BEGIN
if (static_cast<off_type>(_Myios::rdbuf()->pubseekoff(_Off, _Way, ios_base::out)) == -1) {
_Myios::setstate(ios_base::failbit);
}
_CATCH_IO_END
}

return *this;
Expand All @@ -579,10 +589,12 @@ public:
const sentry _Ok(*this);

if (!this->fail()) {
_TRY_IO_BEGIN
return _Myios::rdbuf()->pubseekoff(0, ios_base::cur, ios_base::out);
} else {
return pos_type(-1);
_CATCH_IO_END
}

return pos_type(-1);
}
};

Expand Down
1 change: 1 addition & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ tests\GH_001411_core_headers
tests\GH_001530_binomial_accuracy
tests\GH_001541_case_sensitive_boolalpha
tests\GH_001638_dllexport_derived_classes
tests\GH_001858_iostream_exception
tests\LWG2597_complex_branch_cut
tests\LWG3018_shared_ptr_function
tests\P0019R8_atomic_ref
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/GH_001858_iostream_exception/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\usual_matrix.lst
105 changes: 105 additions & 0 deletions tests/std/tests/GH_001858_iostream_exception/test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#include <cassert>
#include <istream>
#include <ostream>

using namespace std;

template <class CharT>
class throwing_buffer : public basic_streambuf<CharT> {
public:
streampos seekoff(streamoff, ios::seekdir, ios_base::openmode = ios_base::in | ios_base::out) override {
throw 42;
}

streampos seekpos(streampos, ios_base::openmode = ios_base::in | ios_base::out) override {
throw 42;
}

int sync() override {
throw 42;
}

basic_streambuf<CharT>* to_buf() {
return this;
}
};

template <class CharT>
void test_istream_exceptions() {
throwing_buffer<CharT> buffer;

{ // sync
basic_istream<CharT> is(buffer.to_buf());
assert(!is.bad());
is.sync();
assert(is.bad());
}

{ // seekg
basic_istream<CharT> is(buffer.to_buf());
assert(!is.bad());
is.seekg(0);
assert(is.bad());
}

{ // seekg
basic_istream<CharT> is(buffer.to_buf());
assert(!is.bad());
is.seekg(0, ios_base::beg);
assert(is.bad());
}

{ // tellg
basic_istream<CharT> is(buffer.to_buf());
assert(!is.bad());
is.tellg();
assert(is.bad());
}
}


template <class CharT>
void test_ostream_exceptions() {
throwing_buffer<CharT> buffer;

{ // flush
basic_ostream<CharT> os(buffer.to_buf());
assert(!os.bad());
os.flush();
assert(os.bad());
}

{ // seekp
basic_ostream<CharT> os(buffer.to_buf());
assert(!os.bad());
os.seekp(0);
assert(os.bad());
}

{ // seekp
basic_ostream<CharT> os(buffer.to_buf());
assert(!os.bad());
os.seekp(0, ios_base::beg);
assert(os.bad());
}

{ // tellp
basic_ostream<CharT> os(buffer.to_buf());
assert(!os.bad());
os.tellp();
assert(os.bad());
}
}

int main() {
test_istream_exceptions<char>();
test_istream_exceptions<wchar_t>();

test_ostream_exceptions<char>();
test_ostream_exceptions<wchar_t>();
}

0 comments on commit 3c59e25

Please sign in to comment.