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 x
s for a while, and then Ctrl+C the client, terminating it, the server std::terminate
s 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