"Terminate called after throwing an instance of 'std::__ios_failure'" when trying to catch exception from `boost::asio::ip::tcp::iostream`

Viewed 1181

I wrote a simple blocking server which waits for a single client and floods it.

I use boost::asio::ip::tcp::iostream class for interacting with the client as I want to use formatted I/O in the future. I also would like to use exceptions for error handling instead of manual flags checks after each operation, so I called .exceptions() in a fashion similar to basic_ios::exceptions (I assume Boost derives from the latter, doesn't it?).

Here is the resulting code:

#include <boost/asio.hpp>
#include <exception>
#include <iostream>
#include <sstream>
#include <utility>

using boost::asio::ip::tcp;

int main() {
    try {
        try {
            boost::asio::io_context io_context;
            tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 10000));
            std::cout << "Listening at " << acceptor.local_endpoint() << "\n";

            tcp::iostream client(acceptor.accept());
            client.exceptions(std::ios_base::failbit | std::ios_base::badbit |
                              std::ios_base::eofbit);  // (1)
            while (client << "x\n") {
            }
            std::cout << "Completed\n";
        } catch (std::exception &e) {
            std::cout << "Exception: " << e.what() << "\n";
        }
    } catch (...) {
        std::cout << "Unknown exception\n";
    }
    return 0;
}

Unfortunately, it looks like some exceptions are still falling through the cracks. If I start the server, connect via nc localhost 10000, look at xs for a while, and then Ctrl+C the client, terminating it, the server std::terminates with the following error message:

This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
terminate called after throwing an instance of 'std::__ios_failure'
  what():  basic_ios::clear: iostream error

If I comment out the (1) line, everything works flawlessly and the server terminates with a Completed message when the client disconnects.

I've tried it both on Windows (g++ (Rev6, Built by MSYS2 project) 10.2.0 and Boost 1.75.0-3) and Ubuntu 20.04 (g++-10 (Ubuntu 10.2.0-5ubuntu1~20.04) 10.2.0 and Boost 1.71.0.0ubuntu2).

What am I doing wrong?

GDB session on Ubuntu shows that the exception is thrown from inside a destructor, which is presumably noexcept, which is kind of weird:

#0  0x00007ffff7e86762 in __cxa_throw () from /lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00007ffff7e7dc63 in std::__throw_ios_failure(char const*) () from /lib/x86_64-linux-gnu/libstdc++.so.6
#2  0x00007ffff7ef0dd2 in std::basic_ios<char, std::char_traits<char> >::clear(std::_Ios_Iostate) ()
   from /lib/x86_64-linux-gnu/libstdc++.so.6
#3  0x00007ffff7f0f28e in std::ostream::sentry::~sentry() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#4  0x00007ffff7f0f975 in std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_trait
s<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long) ()
   from /lib/x86_64-linux-gnu/libstdc++.so.6
#5  0x00007ffff7f0fd5c in std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(s
td::basic_ostream<char, std::char_traits<char> >&, char const*) () from /lib/x86_64-linux-gnu/libstdc++.so.6
#6  0x000055555555d3a8 in main () at test.cpp:19
0 Answers
Related